JavaRush /Курсы /JAVA 25 SELF /ProcessBuilder — запуск внешних процессов

ProcessBuilder — запуск внешних процессов

JAVA 25 SELF
61 уровень , 0 лекция
Открыта

1. Что такое процессы в ОС и зачем их запускать из Java

Процессы: от JVM к bash и обратно

Когда вы включаете компьютер и открываете браузер, мессенджер или игру — всё это отдельные процессы. Операционная система запускает для каждой программы собственный «мини-мир»: выделяет память, время процессора, разрешает работать с файлами и сетью. Так программы живут рядом, но не мешают друг другу.

Java-программа — не исключение. Когда вы запускаете java MyApp, система создаёт под неё отдельный процесс со всеми нужными ресурсами. Внутри него уже работает ваша программа: считает, рисует, читает файлы — всё, что ей положено.

Но иногда одной Java мало. Бывает, нужно попросить о помощи другую программу — запустить архиватор, чтобы упаковать файлы, вызвать ffmpeg, чтобы обработать видео, или просто узнать, какая версия Java установлена на компьютере. Это и есть запуск внешнего процесса: Java говорит системе «вызови мне вот эту утилиту», а потом получает результат её работы.

По сути, это способ сделать программу более гибкой: объединить разные инструменты, автоматизировать рутину или встроить вашу логику в уже существующие системные процессы. Иногда проще попросить внешнюю команду сделать часть работы, чем изобретать велосипед в коде.

JVM vs. внешний процесс

JVM-процесс — ваша программа, выполняющаяся в виртуальной машине Java.

Внешний процесс — любая другая программа: калькулятор, Python-скрипт, командная строка, даже другой экземпляр Java.

2. Класс ProcessBuilder

В «древние» времена Java запускала процессы через метод Runtime.getRuntime().exec(). Это был не самый удобный и безопасный способ — как попытка забить гвоздь микроскопом. Поэтому с Java 5 появился класс ProcessBuilder, который позволяет создавать, настраивать и запускать внешние процессы более гибко и понятно.

ProcessBuilder — это такой «конструктор», который позволяет заранее задать все параметры будущего процесса: команду, аргументы, рабочую папку, переменные окружения и т.д.

Синтаксис: создание процесса

ProcessBuilder pb = new ProcessBuilder("команда", "аргумент1", "аргумент2", ...);
  • Первый аргумент — имя команды (например, "ls", "dir", "ping", "java").
  • Остальные — параметры для команды.

Пример: запуск команды ls (Linux/Mac) или dir (Windows)

ProcessBuilder pb;
if (System.getProperty("os.name").toLowerCase().contains("win")) {
    pb = new ProcessBuilder("cmd.exe", "/c", "dir");
} else {
    pb = new ProcessBuilder("ls", "-l");
}

Кстати, на Windows команды вроде dir, copy и т.п. — это не отдельные исполняемые файлы, а «встроенные» в командную строку (cmd.exe) команды. Поэтому их нужно запускать через cmd.exe /c ....

Пример: запуск простого процесса

ProcessBuilder pb = new ProcessBuilder("echo", "Hello, Java!");

3. Настройка среды процесса

Передача аргументов. Аргументы команды передаются отдельными строками:

ProcessBuilder pb = new ProcessBuilder("ping", "google.com");

Указание рабочей директории. По умолчанию процесс запускается в той же папке, что и ваша программа. Но можно явно указать другую директорию:

pb.directory(new java.io.File("/tmp"));      // Для Linux/Mac
pb.directory(new java.io.File("C:\\Temp"));  // Для Windows

Изменение переменных окружения. У каждого процесса есть свой набор переменных окружения (environment variables). Их можно добавить или изменить:

pb.environment().put("MY_VAR", "HelloFromJava");

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

4. Запуск процесса

Метод start(). Когда вы всё настроили, пора запускать процесс:

Process process = pb.start();

Метод start() возвращает объект Process, который позволяет управлять запущенной программой: читать её вывод, писать в её ввод, завершать её и т.д.

Обработка исключений. start() может выбросить IOException, если команда не найдена, нет прав или возникла другая ошибка запуска.

Пример:

try {
    Process process = pb.start();
    // Работаем с процессом...
} catch (IOException e) {
    System.out.println("Ошибка запуска процесса: " + e.getMessage());
}

5. Практика: Запуск простых команд

Пример 1: Вывести список файлов в папке

import java.io.*;

public class ProcessDemo {
    public static void main(String[] args) {
        // Определяем команду в зависимости от ОС
        ProcessBuilder pb;
        if (System.getProperty("os.name").toLowerCase().contains("win")) {
            pb = new ProcessBuilder("cmd.exe", "/c", "dir");
        } else {
            pb = new ProcessBuilder("ls", "-l");
        }

        try {
            Process process = pb.start();

            // Читаем вывод процесса (stdout)
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream())
            );
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            // Ждём завершения процесса
            int exitCode = process.waitFor();
            System.out.println("Процесс завершён с кодом: " + exitCode);

        } catch (IOException | InterruptedException e) {
            System.out.println("Ошибка: " + e.getMessage());
        }
    }
}

Что здесь происходит?

  • Определяем, какая ОС — чтобы выбрать правильную команду.
  • Создаём ProcessBuilder с нужной командой.
  • Запускаем процесс через start().
  • Читаем строки из stdout процесса и выводим их на экран.
  • Ждём завершения процесса (waitFor()).
  • Выводим код возврата (0 — успех, другое — ошибка).

Пример 2: Запуск java -version

ProcessBuilder pb = new ProcessBuilder("java", "-version");
try {
    Process process = pb.start();

    // java -version пишет в stderr, поэтому читаем getErrorStream()
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(process.getErrorStream())
    );
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
    process.waitFor();
} catch (IOException | InterruptedException e) {
    e.printStackTrace();
}

Важный нюанс: Некоторые команды (например, java -version) выводят информацию не в стандартный вывод (stdout), а в поток ошибок (stderr). Поэтому иногда нужно читать process.getErrorStream().

6. Кроссплатформенность: различия между Windows и Linux/Mac

  • Команды и их параметры могут отличаться.
  • Пути к файлам пишутся по-разному (C:\Temp vs /tmp).
  • Некоторые команды (например, ls, cat) есть только в Unix-подобных системах, а в Windows их заменяют аналоги (dir, type).
  • На Windows встроенные команды запускаются только через cmd.exe /c команда.

Пример проверки ОС:

String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
    // Windows
} else if (os.contains("mac")) {
    // macOS
} else if (os.contains("nix") || os.contains("nux")) {
    // Linux
}

Совет: Всегда тестируйте ваши программы на целевых ОС, если рассчитываете на кроссплатформенность.

7. Таблица: основные методы и возможности ProcessBuilder

Метод/поле Назначение Пример использования
new ProcessBuilder(String...)
Создать процесс с командой и аргументами
new ProcessBuilder("ls", "-l")
.directory(File)
Задать рабочую директорию
.directory(new File("/tmp"))
.environment()
Получить/изменить переменные окружения
.environment().put("VAR", "value")
.start()
Запустить процесс
Process p = pb.start()
Process.getInputStream()
Получить stdout процесса
InputStream
Process.getErrorStream()
Получить stderr процесса
InputStream
Process.getOutputStream()
Получить stdin процесса
OutputStream
Process.waitFor()
Ждать завершения процесса
int code = p.waitFor()
Process.exitValue()
Получить код возврата процесса
int code = p.exitValue()

8. Типичные ошибки при запуске внешних процессов

Ошибка №1: Команда не найдена. Если вы ошиблись в названии команды или она отсутствует в системе, получите IOException: Cannot run program .... Например, попытка запустить ls на Windows.

Ошибка №2: Неправильная передача аргументов. Не нужно объединять всю команду в одну строку! Правильно: new ProcessBuilder("ping", "google.com"). Неправильно: new ProcessBuilder("ping google.com").

Ошибка №3: Не учли отличия ОС. Команда, которая отлично работает на Linux, может не существовать на Windows, и наоборот. Всегда проверяйте ОС и адаптируйте команду.

Ошибка №4: Не обработали вывод процесса. Если не читать вывод процесса, он может «зависнуть» из-за переполнения буфера. Даже если вы не собираетесь использовать вывод — читайте его и, например, просто игнорируйте.

Ошибка №5: Не закрыли потоки. Потоки процесса нужно закрывать после использования, чтобы не было утечек ресурсов.

Ошибка №6: Не обработали исключения. Запуск внешнего процесса — рискованное дело. Всегда используйте try-catch и информируйте пользователя об ошибках.

1
Задача
JAVA 25 SELF, 61 уровень, 0 лекция
Недоступна
Системный инспектор 🖥️
Системный инспектор 🖥️
1
Задача
JAVA 25 SELF, 61 уровень, 0 лекция
Недоступна
Цифровой Следопыт 📁
Цифровой Следопыт 📁
Комментарии (3)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Ioanna Polyak Уровень 43
10 декабря 2025
Lvl UP! 61! ^|^
Anton Pohodin Уровень 26
25 ноября 2025
Level 61! ^_^
Andrey Уровень 1
16 ноября 2025
61