Process.getInputStream: примеры (JAVA)
Process.getInputStream: InputStreamОбщее описание метода Process.getInputStream()
Метод Process.getInputStream() класса java.lang.Process предоставляет поток для чтения стандартного вывода запущенного процесса (stdout дочернего процесса). Метод не принимает аргументов и возвращает объект java.io.InputStream. Полученный поток позволяет получить байтовый вывод процесса в текущем JVM-процессе.
Когда применяется: при необходимости выполнения внешней программы и обработки её вывода из Java-кода, например при парсинге результатов утилит системы, запуске консольных инструментов или организации конвейеров между процессами.
Аргументы и возвращаемое значение
Аргументы: отсутствуют. Метод всегда вызывается как process.getInputStream(), где process - объект типа Process.
Возвращаемое значение: java.io.InputStream. Поток может быть пустым, блокирующим (ожидающим данных) или закрытым, в зависимости от состояния дочернего процесса и его стандартного вывода.
Поведение и особенности
- Поток представляет stdout дочернего процесса, а не stdin. Для записи в stdin дочернего процесса применяется
Process.getOutputStream(). - Метод сам по себе не бросает проверяемых исключений, но операции чтения из возвращенного
InputStreamмогут бросатьIOException. - Если stdout дочернего процесса производит большой объем данных, отсутствие чтения из потока может привести к заполнению буфера операционной системы и блокировке дочернего процесса.
- Кодировка символов не задаётся в самом InputStream. Для получения текста необходимо оборачивать поток в
InputStreamReaderс указанием кодировки либо применятьBufferedReaderдля чтения строк. - Слияние stdout и stderr выполняется опцией
ProcessBuilder.redirectErrorStream(true), после чегоgetInputStream()будет содержать объединенный вывод. - В Java 9+ доступна удобная операция
InputStream.transferTo(OutputStream), упрощающая копирование данных изgetInputStream()в целевой поток.
Простые примеры чтения stdout процесса
Примеры показывают разные способы чтения вывода: чтение строк, чтение байтов, использование transferTo. В примерах показаны команды для Unix и Windows по возможности. Результаты представлены в блоке результата.
// Пример 1. Чтение строк (Unix)
import java.io.*;
public class Example1 {
public static void main(String[] args) throws Exception {
Process p = new ProcessBuilder("echo", "Hello from process").start();
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())) ) {
String line;
while ((line = br.readLine()) != null) {
System.out.println("OUT: " + line);
}
}
p.waitFor();
}
}
OUT: Hello from process
// Пример 2. Чтение байтов
import java.io.*;
public class Example2 {
public static void main(String[] args) throws Exception {
Process p = new ProcessBuilder("echo", "byte output").start();
InputStream in = p.getInputStream();
int b;
while ((b = in.read()) != -1) {
System.out.print((char) b);
}
p.waitFor();
}
}
byte output
// Пример 3. transferTo (Java 9+)
import java.io.*;
public class Example3 {
public static void main(String[] args) throws Exception {
Process p = new ProcessBuilder("echo", "transferTo example").start();
try (InputStream in = p.getInputStream(); OutputStream out = System.out) {
in.transferTo(out);
}
p.waitFor();
}
}
transferTo example
Связанные методы в Java
- Process.getErrorStream() - поток для чтения стандартного потока ошибок (stderr). Предпочтителен при необходимости отдельной обработки ошибок.
- Process.getOutputStream() - поток для записи в стандартный ввод дочернего процесса (stdin). Используется для передачи данных в запущенную программу.
- ProcessBuilder.redirectOutput() и redirectErrorStream(true) - позволяют перенаправить вывод в файл или объединить stderr и stdout. Удобны при желании избежать явного чтения потоков из Java кода.
- ProcessHandle и расширенная Process API (Java 9+) - дают дополнительную информацию о процессе, но не заменяют getInputStream для чтения stdout.
Выбор зависит от задачи: для простого чтения stdout применяется getInputStream; для объединенного вывода подходит redirectErrorStream; для записи в процесс используется getOutputStream; для логирования в файл предпочтительны redirectOutput или передача вывода на файловую систему.
Аналоги в других языках
Краткое сравнение с примерами поведения и отличий.
- Python
import subprocess p = subprocess.Popen(["echo", "hello"], stdout=subprocess.PIPE) out = p.stdout.read() print(out.decode().strip())hello
Отличие: Python предоставляет stdout как файловый объект сразу при создании Popen. Кодировка должна указываться при декодировании.
- Node.js (JavaScript)
const { spawn } = require('child_process'); const p = spawn('echo', ['hello']); p.stdout.on('data', (data) => { console.log(data.toString().trim()); });hello
Отличие: поток stdout в Node.js событийно ориентирован, подходит для неблокирующего чтения.
- C#
using System.Diagnostics; var p = new Process(); p.StartInfo.FileName = "cmd"; p.StartInfo.Arguments = "/c echo hello"; p.StartInfo.RedirectStandardOutput = true; p.Start(); string out = p.StandardOutput.ReadToEnd(); Console.WriteLine(out.Trim());hello
Отличие: .NET предоставляет обертки StreamReader для StandardOutput и опции перенаправления через StartInfo.
- Go
package main import ( "fmt" "os/exec" ) func main() { cmd := exec.Command("echo", "hello") out, _ := cmd.Output() fmt.Print(string(out)) }hello
Отличие: Go возвращает собранный вывод удобным методом Output или предоставляет StdoutPipe для стриминга.
- PHP
$proc = popen('echo hello', 'r'); $out = stream_get_contents($proc); pclose($proc); echo trim($out);hello
- Kotlin
val p = ProcessBuilder("echo", "hello").start() val out = p.inputStream.bufferedReader().readText() println(out.trim())hello
Отличие: Kotlin использует тот же JVM API, но предоставляет удобные расширения для работы с потоками.
- Lua
local f = io.popen('echo hello') local out = f:read('*a') f:close() print(out:match('%S+'))hello
- SQL
SQL не выполняет внешние процессы напрямую. В СУБД иногда доступны расширения или процедуры для вызова ОС, но они специфичны для платформы и не имеют прямого аналога getInputStream.
Типичные ошибки и их проявления
- Неправильное понимание: ожидание в getInputStream вывода stdin. Последствие: поиск данных в неправильном потоке.
- Не чтение stderr: если программа пишет ошибки в stderr, getInputStream() не покажет их без redirectErrorStream(true). Пример: программа пишет в stderr, а код читает только stdout - вывод отсутствует.
- Блокировка из-за незачитанных потоков: дочерний процесс может зависнуть при заполнении системного буфера. Часто проявляется как вечное ожидание p.waitFor().
- Неправильная кодировка: чтение байтов без указания кодировки приводит к искажению символов при не-UTF8 выводе.
Пример ошибки: зависание из-за отсутствия чтения stderr и stdout одновременно.
// Ошибочный пример: может зависнуть при большом выводе
Process p = new ProcessBuilder("someCommandThatPrintsALot").start();
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
// читается только stdout
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
p.waitFor();
Программа может зависнуть из-за переполнения stderr буфера, если процесс пишет и туда
Пример ошибки с кодировкой
// Чтение без указания кодировки приводит к возможному искажению
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s = br.readLine();
System.out.println(s);
Если вывод в CP1251, результат в консоли UTF-8 будет искажен
Рекомендации по устранению: одновременное чтение stderr и stdout (в отдельных потоках) или объединение потоков, указание кодировки при создании InputStreamReader, использование try-with-resources для закрытия потоков.
Изменения и эволюция API
Сам метод Process.getInputStream() присутствует в Java с ранних версий и концептуально не менялся. Основные улучшения вокруг интерфейса Process появились в следующих версиях:
- Java 5: ввод ProcessBuilder для более гибкого создания процессов.
- Java 7: улучшения по управлению вводом/выводом и try-with-resources, упрощение закрытия потоков.
- Java 9: добавлен метод
InputStream.transferTo(OutputStream), который упрощает передачу данных из getInputStream; введенProcessHandleи дополнения к управлению процессом.
Изменений в сигнатуре getInputStream не происходило, но появление вспомогательных методов и API делает работу с потоком более удобной в новых версиях Java.
Расширенные и нетипичные примеры использования
Несколько продвинутых сценариев: параллельное чтение stdout и stderr, потоковая передача вывода в файл, чтение бинарных данных и парсинг прогресс-вывода.
// Пример A. Параллельное чтение stdout и stderr, чтобы избежать блокировок
import java.io.*;
import java.util.concurrent.*;
public class ParallelStreams {
public static void main(String[] args) throws Exception {
Process p = new ProcessBuilder("bash", "-c", "echo out; echo err 1>&2; sleep 1; echo out2").start();
ExecutorService ex = Executors.newFixedThreadPool(2);
Callable readStream(InputStream in) {
return () -> {
try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
StringBuilder sb = new StringBuilder();
String s;
while ((s = br.readLine()) != null) {
sb.append(s).append('\n');
}
return sb.toString();
}
};
}
Future stdout = ex.submit(readStream(p.getInputStream()));
Future stderr = ex.submit(readStream(p.getErrorStream()));
int code = p.waitFor();
System.out.println("exit=" + code);
System.out.println("STDOUT:\n" + stdout.get());
System.out.println("STDERR:\n" + stderr.get());
ex.shutdown();
}
}
exit=0 STDOUT: out out2 STDERR: err
// Пример B. Стриминг вывода процесса в файл с использованием transferTo (Java 9+)
import java.io.*;
public class StreamToFile {
public static void main(String[] args) throws Exception {
Process p = new ProcessBuilder("yes", "line").start(); // генерирует много строк
try (InputStream in = p.getInputStream();
OutputStream fos = new FileOutputStream("out.txt")) {
// ограничение: читается первые N байт при помощи промежуточного буфера
byte[] buf = new byte[8192];
int read, total = 0, limit = 100_000; // например 100 KB
while ((read = in.read(buf)) != -1 && total < limit) {
int toWrite = Math.min(read, limit - total);
fos.write(buf, 0, toWrite);
total += toWrite;
}
}
p.destroyForcibly();
}
}
Результат: файл out.txt с частью вывода команды yes
// Пример C. Чтение бинарного вывода и поиск сигнатуры
import java.io.*;
public class BinaryRead {
public static void main(String[] args) throws Exception {
Process p = new ProcessBuilder("xxd", "-p", "/bin/ls").start();
try (InputStream in = p.getInputStream()) {
byte[] buffer = in.readAllBytes(); // Java 9+
// поиск подпоследовательности, например первые 4 байта
for (int i = 0; i < Math.min(16, buffer.length); i++) {
System.out.printf("%02x ", buffer[i]);
}
System.out.println();
}
p.waitFor();
}
}
Пример вывода: шестнадцатеричные байты начала файла
// Пример D. Выполнение команды с вводом и чтением результата (двунаправленное общение)
import java.io.*;
public class Bidirectional {
public static void main(String[] args) throws Exception {
Process p = new ProcessBuilder("python3", "-u", "-c", "print(input())").start();
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
bw.write("Hello Python\n");
bw.flush();
String reply = br.readLine();
System.out.println("Reply: " + reply);
}
p.waitFor();
}
}
Reply: Hello Python
Пояснения: в сложных сценариях рекомендуется использовать отдельные потоки для чтения stdout и stderr, задавать кодировку явно, применять временные файлы или transferTo при больших объёмах и аккуратно завершать процессы через destroy/destroyForcibly при необходимости.
джава Process.getInputStream function comments
- джава Process.getInputStream - аргументы и возвращаемое значение
- Функция java Process.getInputStream - описание
- Process.getInputStream - примеры
- Process.getInputStream - похожие методы на java
- Process.getInputStream на javascript, c#, python, php
- Process.getInputStream изменения java
- Примеры Process.getInputStream на джава