Я знаю, что канонический способ обработки потоков вывода / ошибок внешнего Процесса в Java - это использование двух дополнительных потоков для извлечения данных из потоков вывода и ошибок, чтобы процесс не мог быть заблокирован.
А что насчет следующего?
public static void main(String[] args) throws IOException, InterruptedException {
ProcessBuilder processBuilder = new ProcessBuilder(args);
Process process = processBuilder.start();
InputStream outputStream = null, errorStream = null;
ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream();
ByteArrayOutputStream errorBuffer = new ByteArrayOutputStream();
try {
outputStream = process.getInputStream();
errorStream = process.getErrorStream();
byte[] tmp = new byte[1024];
while (true) {
int outputBytes = readAvailablOnce(outputStream, outputBuffer, tmp);
int errorBytes = readAvailablOnce(errorStream, errorBuffer, tmp);
if (outputBytes == 0 && errorBytes == 0) {
try {
process.exitValue();
break;
} catch (IllegalThreadStateException e) {
// keep on looping
}
}
}
readAvailableAll(outputStream, outputBuffer, tmp);
readAvailableAll(errorStream, errorBuffer, tmp);
} finally {
closeQuietly(outputStream);
closeQuietly(errorStream);
}
System.out.println(outputBuffer.toString("ASCII"));
System.err.println(errorBuffer.toString("ASCII"));
System.err.println("exit code: " + process.exitValue());
}
private static void closeQuietly(InputStream in) {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// ignored
}
}
}
private static int readAvailablOnce(
InputStream inputStream, OutputStream outputStream, byte[] buffer)
throws IOException {
int bytesRead = 0;
if (inputStream.available() > 0) {
bytesRead = inputStream.read(buffer);
outputStream.write(buffer, 0, bytesRead);
}
return bytesRead;
}
private static void readAvailableAll(
InputStream inputStream, OutputStream outputStream, byte[] buffer)
throws IOException {
if (inputStream.available() > 0) {
int bytesRead = 0;
while ((bytesRead = inputStream.read(buffer)) >= 0) {
outputStream.write(buffer, 0, bytesRead);
}
}
}
Это на самом деле работает нормально в тех нескольких примерах, которые я пробовал (запуск "dir", "ps aux" и т. Д.).
У него также есть недостаток, заключающийся в том, что вы не можете легко обрабатывать выходные данные построчно (здесь вы буферизуете все перед тем, как что-либо делать), если только вы не начинаете делать более или менее сложные вещи с помощью Buffers и CharsetDecoders.это выглядит полезным для всего без недопустимо большого вывода (хотя ничто не заставляет нас буферизовать весь вывод перед его использованием).
Я пробовал только 1.5 и 1.6 JVM (Windows XP и Linux).
Кроме того, этот код предполагает, что последние выходные биты процесса будут легко доступны для чтения (InputStream.available ()> 0).
Кто-нибудь может знать, что (или если что-то) не так с этим кодом (или есть идея получше)?