При создании оболочки для консольного приложения я столкнулся с этой странной проблемой, когда входной поток, подключенный к выходу (стандартный вывод) внешнего процесса, полностью пуст до внешний выходы процесса.Нет ввода InputStream ProcessBuilder до закрытия внешнего процесса
Мой код, как показано ниже:
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
public class Example{
public static void main(String args[]) throws IOException{
File executable = ...
ProcessBuilder pb = new ProcessBuilder(executable.getCanonicalPath());
pb.redirectErrorStream(true);
Process p = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), Charset.forName("UTF-8")));
String line;
while((line = br.readLine()) != null){
System.out.println(line);
}
}
}
Я пробовал несколько вариантов чтения из входного потока и все это привело в такое же поведение.
Я пробовал:
CharBuffer charBuf = CharBuffer.allocate(1000);
InputStreamReader isr = new InputStreamReader(p.getInputStream(), Charset.forName("UTF-8"));
while(isr.read(charBuf) != -1){
System.out.print(charBuf.flip().toString());
}
и
byte[] buf = new byte[1000];
int r;
while((r = p.getInputStream().read(buf)) != -1){
System.out.print(new String(buf, 0, r));
}
все безрезультатно.
Где-то вдоль линии вывод внешнего процесса буферизуется (неопределенно), и я не могу понять, где именно. Загрузка процесса из командной строки, кажется, работает нормально, когда я вижу вывод, выходящий мгновенно. Самая странная часть - это тот факт, что окончание внешнего процесса приводит к потоку всего «буферизованного» вывода сразу (много чего).
К сожалению, у меня нет доступа к источнику внешнего процесса, но при условии, что он записывает в стандартный вывод stdout, когда в консоли не должно быть никакого изменения там (насколько я знаю).
Любые идеи приветствуются.
Edit:
Один ответ рекомендовал мне переписать читатель для вывода и ошибок потоков для запуска в отдельном потоке. Моя фактическая реализация делает это! И все же проблема все еще существует. Код, указанный выше, представляет собой SSCCE моего фактического кода, сконденсированного для удобства чтения, фактический код включает отдельный поток для чтения из InputStream
.
Edit 2:
Пользователь FoggyDay, кажется, дал ответ, который определяет, как поведение изменения буферизации вывода при выводе между консолью и не-консолей. В то время как процессы, которые обнаруживают, что они пишут на консоль, используют буферизацию строк (буферизованная очистка каждой новой строки), запись в неконсоли (все, что она обнаруживает, чтобы не быть консолью) может быть полностью буферизована (до размера примерно 8K). Если я делаю спам внешнего процесса (8K lorem ipsum в цикле for), выход действительно появляется. Думаю, теперь мой вопрос заключается в том, как заставить мою java-программу запускать буферизацию по внешнему процессу.
Зачем использовать BufferedReader, если вы не хотите буферизации? Вместо этого я могу переключиться на «java.util.Scanner». –
@ElliottFrisch Первоначально я хотел получить некоторую форму буферизации, но, учитывая, что это не совсем сработало, я начал использовать «CharBuffer» и сортировать, чтобы попробовать устранить проблему. моя последняя попытка заключалась в том, что я читал исходный поток InputStream напрямую и все же, выход не отображается. Учитывая, что Scanner построен поверх исходного InputStream, я не вижу, как он будет работать, но я все равно попробую. – initramfs
Я предполагаю, что вы уже пробовали свой код с другими исполняемыми файлами и видели, что его выход доступен до завершения процесса? Любой случай, когда этот исполняемый файл делает что-то напуганное, например, проверяет, перенаправляется ли выход? –