Подтвердить что ты не робот

BufferedReader.readLine блокирует мою программу, но BufferedReader.read() читает правильно

У меня есть фрагмент следующим образом:

Process proc = Runtime.getRuntime().exec(command);
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String line = br.readLine();

Теперь в приведенном выше коде я уверен, что процесс всегда будет иметь линейный ввод, поэтому я не использовал какой-либо цикл while или любую нулевую проверку. Проблема заключается в readLine-блоках. Единственной причиной, о которой я знал, является поток, не имеющий данных для чтения и, следовательно, readLine продолжает ждать. Чтобы проверить это, я удалил readLine и использовал функцию read() следующим образом:

Process proc = Runtime.getRuntime().exec( command );
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
int a;
while((a=br.read())!=-1){
    char ch = (char) a;
    if(ch == '\n')
        System.out.print("New line "+ch);
    if(ch == '\r')
        System.out.print("Carriage return "+ch);
    System.out.print(ch);
}

К моему удивлению, этот код работал и печатал сообщения messags New line и Carriage. Теперь мне интересно, почему блок readLine? Доступны данные, которые завершаются новой строкой. Что еще может быть причиной?

Примечание: вышеописанное работало время от времени! Может быть, один раз из 15 раз.
Примечание. Я также попытался использовать ProcessBuilder, но такое же поведение.

UPDATE: Поэтому я переключился на ProcessBuilder, а затем перенаправил errorStream, и теперь я получаю как поток ввода, так и поток ошибок сразу, когда я обрабатываю process.getInputStream, и это отлично работает. Ниже приведен фрагмент.

ProcessBuilder pb = new ProcessBuilder(command.split(" "));
pb..redirectErrorStream(true);
Process proc = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = br.readLine();
//Now I get both input and error stream.

Я хотел бы отличить поток ошибок от потока ввода, но с помощью этого метода они все запутались! Любые идеи по этому поводу?

4b9b3361

Ответ 1

Итак, чтобы не допустить, чтобы поток ошибок и поток данных были объединены, просто удалите строку pb.redirectErrorStream(true);

Потому что, как сказано в java-документе:

если это свойство истинно, тогда любой вывод ошибки, сгенерированный подпроцессами, впоследствии запущенный этим методом start() объекта, будет объединен со стандартным выходом, так что оба могут быть прочитаны с использованием метода Process.getInputStream(). Это упрощает корреляцию сообщений об ошибках с соответствующим выходом. Начальное значение ложно.

Вызывая pb.redirectErrorStream(true);, вы объединяете оба вывода.

Ответ 2

Вы можете использовать потоки, чтобы избежать этого.

Как один подчиненный поток, который будет отвечать за чтение. Это не остановит ваш прогресс в программе.

Ответ 3

Я думаю, проблема заключается не в том, что стандартная ошибка блокируется, а в том, что стандартный вывод блокирует, вызывая приложение, которое вы вызываете для блокировки.

Стандартный вывод обычно буферизуется. Если процесс, который вы вызываете, записывает меньше стандартного вывода, чем размер буфера, все хорошо, и он может достичь кода, который записывается в стандартную ошибку. Если процесс заполняет буфер, его попытка записи на стандартный вывод блокируется, и он никогда не достигнет точки, где он записывает стандартную ошибку.

Это может быть причина, по которой вы видите, что она работает иногда - иногда стандартный вывод не заполняет буфер. Это также может быть связано с тем, что он работает через долгое время: в конечном итоге запись на стандартный вывод времени истекает.

В качестве демонстрации этот простой процесс всегда блокируется, как вы описываете на моей машине Windows 8:

public class Proc {

    public static void main(String[] args) {
        for(int i=0;i<1000;i++) {
            System.out.print("More data ");
        }
        System.out.println();
        System.err.println("An error line");
    }
}

Ответ 4

getErrorStream утверждает следующее Возвращает входной поток, подключенный к выходу ошибки подпроцесса. Поток получает данные, переданные по каналу из вывода ошибки процесса, представленного этим объектом Process. Если стандартная ошибка подпроцесса была перенаправлена ​​с помощью ProcessBuilder.redirectError или ProcessBuilder.redirectErrorStream, тогда этот метод вернет пустой поток ввода.

а ReadLine указывает следующее Читает строку текста. Линия считается завершенной любым из строк ('\n'), возвратом каретки ('\ r') или возвратом каретки, за которым следует сразу строка.

На основе пояснения, предоставленного API. readline ждет бесконечно, чтобы получить фид строки или возврат каретки, где, поскольку processbuilder возвращает NULL, поэтому readLine заканчивается для того же самого.