Во-первых, стоит отметить, что вы можете упростить это, избегая внешнего процесса и используя 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-программы.Без этого у вас не было бы указаний на то, почему программа потерпела неудачу.(Это сделало бы то же самое со стандартным вводом и стандартным выводом, если бы мы не перенаправили их.)