Java не запускает команду GZIP при использовании ProcessBuilder - PullRequest
0 голосов
/ 10 октября 2018

У меня определенно установлено GZIP на коробках, где я пробую это.Но когда я запускаю это на Java, я не вижу, как создается заархивированный файл.Файл, с которым я имею дело, является действительно большим файлом, и я бы предпочел не читать его в память.Ниже приведен код, который я написал для этой цели.Я догадываюсь, что это как-то связано с перенаправлениями.

try {
    ProcessBuilder builder = new ProcessBuilder("gzip", "-9", "<", filename, ">", zippedFilename);
    builder.start();
} catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}

1 Ответ

0 голосов
/ 11 октября 2018

Во-первых, стоит отметить, что вы можете упростить это, избегая внешнего процесса и используя Java для выполнения сжатия:

Path input = Paths.get(filename);
Path zipped = Paths.get(zippedFilename);

try (OutputStream out = new GZIPOutputStream(
    new BufferedOutputStream(
        Files.newOutputStream(zipped)))) {

    Files.copy(input, out);
}

Это дает дополнительное преимущество, будучи полностью мультиплатформенным.Не нужно требовать / usr / bin / gzip, не нужно использовать инструменты Unix для Windows.Он не будет реализовывать опцию -9, но я бы проверил, какое дополнительное сжатие фактически получает эта опция, и оценил, стоит ли иметь менее переносимую программу.

Для других команд (или если -9 является критически важным), команда ProcessBuilder не может выполнить перенаправление ввода и вывода с < и >, по той же причине, что программа на С не сможет выполнить перенаправление с помощью вызова, подобного:

/* Does not work. */
execl("/usr/bin/gzip", "gzip", "-9", "<", filename, ">", zippedFilename, (char *)NULL);

Когда вы запускаете команду в оболочке (например, bash), оболочка перехватывает < и >, отбирает их и их последующие аргументы из команды и вызывает саму программу без них.Таким образом, введя следующее:

gzip -9 < filename > filename.gz

фактически заставляет оболочку запускать gzip только с одним аргументом: -9.Затем оболочка читает из filename и передает его в стандартный входной дескриптор процесса программы gzip.Точно так же оболочка захватывает стандартный вывод из того же самого вызова программы gzip и записывает его в filename.gz.

Пока это происходит, процесс gzip не знает, откуда поступил его ввод, или где еговыход идет.Он просто читает из своего собственного стандартного ввода и пишет в его стандартный вывод.

Когда вы вызываете программу напрямую, вы обходите оболочку, поэтому специальная обработка < и > отсутствует.Это означает, что ваша текущая команда ProcessBuilder является эквивалентом этой команды Unix:

gzip -9 '<' filename '>' filename.gz

, что означает, что вы вызываете gzip с одним параметром и четырьмя аргументами файла, в результате чего gzip сначала ищет файл с именемодин символ длиной, файл с буквальным именем <, затем запишите его сжатую версию в <.gz.Затем он будет делать то же самое с файлом с именем filename, затем с именем >, затем с именем filename.gz.

Так что, как вы можете видеть, команды Unix ничего не знают о перенаправлении.Символы < и > не могут быть переданы им напрямую.

Однако вы можете смоделировать перенаправление с помощью ProcessBuilder:

ProcessBuilder builder = new ProcessBuilder("gzip", "-9");
builder.inheritIO();
builder.redirectInput(new File(filename));
builder.redirectOutput(new File(zippedFilename));

Process process = builder.start();

Вызов метода методаоризонт () вызовет внешний вызов.стандартная ошибка процесса (то есть любые сообщения об ошибках), появляющиеся в стандартной ошибке Java-программы.Без этого у вас не было бы указаний на то, почему программа потерпела неудачу.(Это сделало бы то же самое со стандартным вводом и стандартным выводом, если бы мы не перенаправили их.)

...