Процесс запущен, когда ProcessBuilder прекратил предоставлять данные - PullRequest
0 голосов
/ 26 апреля 2020

Мне нужно запустить unix программу из java, работающую на windows. Программа unix принимает имя файла в качестве первого параметра, обрабатывает файл и возвращает обработанный файл на стандартный вывод.

Следующее отлично работает из консоли CMD:

wsl.exe /home/user/process /mnt/c/Users/user/input

Печатает из stdout и stderr в консоль; или я могу перенаправить стандартный вывод в новый файл, который будет весить 1,2 МБ.

Я хочу сделать то же самое с Java. Следующий код является наиболее упрощенной версией

ProcessBuilder toCsv = new ProcessBuilder("wsl.exe", "/home/user/process", "/mnt/c/Users/user/input");
Process proc = toCsv.start();
try (InputStream is = proc.getInputStream()){
 for(int i=0; is.read() != -1; i++) {
   System.out.println(i);
 }
}

. Это всегда останавливается на байте с номером 380927. Отладчик показывает, что он останавливается на FileInputStream.read

  • Я пытался использовать перенаправления на отправить стандартный вывод в файл
  • Я пытался читать только stderr
  • Я пытался читать в другом потоке с waitFor на главном
  • Я пытался читать в другом потоке без mainFor на основной
  • Я пытался читать без Thread.sleep вместо waitFor
  • Я пытался передать "/bin/bash", "-c", exec+" "+execFile ProcessBuilder
  • Я пытался использовать Runtime.exe c вместо ProcessBuilder
  • Я пробовал "/bin/bash", "-c", "while :; do echo 1; done". Это на самом деле превысило ограничение в 380 Кбайт и прошло бесконечно, как и ожидалось.

Что происходит и как это исправить?

PS исходный код для unix исполняемого файла здесь , но я не думаю, что это очень полезно, так как работает от CMD

1 Ответ

0 голосов
/ 26 апреля 2020

Я нашел ответ, когда печатал. Очевидно, вы ДОЛЖНЫ как-то позаботиться о потоках STDERR и STDOUT, они не просто исчезают. Если вы прочитаете только один из них и проигнорируете другой, в конечном итоге буфер игнорируемого станет слишком большим и будет блокироваться до тех пор, пока не будет очищен.

, поэтому добавление следующего кода решило эту проблему

new Thread( () -> {
     try (InputStream es = csvBuilder.getErrorStream() ){
            IOUtils.skip(es, Long.MAX_VALUE);
     } catch (IOException e) {
            throw new RuntimeException(e);
     }
}).start();
...