Конвейер оболочки Java: команда `head` не выводит строки, пока не получит ожидаемое число, даже с `tail -f`JAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Конвейер оболочки Java: команда `head` не выводит строки, пока не получит ожидаемое число, даже с `tail -f`

Сообщение Anonymous »

Я создаю оболочку на Java и сейчас реализую конвейерную логику. Для межпроцессного взаимодействия я создал этот класс:

Код: Выделить всё

public class PipeConnector implements Runnable {
private final Process source;
private final Process target;
private final BufferedReader sourceOutput;
private final BufferedWriter targetInput;

public PipeConnector(Process source, Process target) {
this.source = source;
this.target = target;
sourceOutput = new BufferedReader(new InputStreamReader(source.getInputStream()));
targetInput = new BufferedWriter(new OutputStreamWriter(target.getOutputStream()));
}

private void transmit() throws IOException {
String line;

while ((line = read()) != null && target.isAlive()) {
if (line.isEmpty()) {
if (!target.isAlive()) {
source.destroy();
break;
}

if (!source.isAlive()) {
targetInput.close();
}
} else {
targetInput.write(line + "\n");
targetInput.flush();
}
}

targetInput.close();
}

private String read() throws IOException {
if (sourceOutput.ready()) {
return sourceOutput.readLine();
} else {
return "";
}
}

public void run() {
try {
transmit();
} catch (IOException _) {

}
}
}
В большинстве случаев это работает хорошо, но у меня возникают проблемы с Tail -f. Вот пример использования:

Код: Выделить всё

ProcessBuilder cmdTail = new ProcessBuilder(
List.of("tail", "-f", "test.txt"))
.directory(new File("/home/lowkkid/test"));

ProcessBuilder cmdHead = new ProcessBuilder(List.of("head", "-n", "6"));

Process processTail = cmdTail.start();
Process processHead = cmdHead.start();

PipeConnector connector = new PipeConnector(processTail, processHead);
new Thread(connector).start();

try (BufferedReader reader = new BufferedReader(
new InputStreamReader(processHead.getInputStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
Если test.txt содержит только 4 строки, приложение запускается и ожидает (что ожидаемо, поскольку head -n 6 ожидает 6 строк в своем стандартном вводе). Однако в этом случае вывод консоли остается пустым. Сначала он должен напечатать эти 4 строки, а затем подождать еще две.
После отладки я понял, что эти 4 строки застревают где-то в целевом процессе, пока их не останется 6. Они успешно записываются в targetInput, но не отображаются в System.out.println(line);. Если я запускаю приложение с файлом test.txt, содержащим 6 или более строк, оно печатает их правильно и завершает работу с кодом 0.
Вопрос: Как заставить эти строки печатать немедленно, до достижения счетчика 6?
P.S. В классе PipeConnector я использую проверку if (sourceOutput.ready()), чтобы избежать блокировки с помощью таких команд, как Tail -f, которые ждут дополнительных входных данных после чтения файла. Без этой проверки readLine() будет блокироваться на неопределенный срок, пока исходный процесс ожидает.

Подробнее здесь: https://stackoverflow.com/questions/798 ... ives-the-e
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»