我肯定在尝试此操作的盒子上安装了GZIP
。但是,当我在Java中运行此文件时,看不到正在创建的压缩文件。我正在处理的文件是非常大的文件,因此我不希望将其读入内存。以下是我为此编写的代码。我的直觉是它与重定向有关。
try {
ProcessBuilder builder = new ProcessBuilder("gzip", "-9", "<", filename, ">", zippedFilename);
builder.start();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
答案 0 :(得分:2)
首先,值得注意的是,您可以通过避免外部过程并使用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);
}
这具有完全多平台的额外优势。在Windows上不需要/ usr / bin / gzip,也不需要Unix工具。它不会实现-9
选项,但是我会检查该选项实际上能获得多少额外的压缩,并权衡使用一个不那么便携的程序是否值得。
对于其他命令(或者如果-9
非常重要),由于C程序会出于相同的原因,ProcessBuilder命令无法使用<
和>
进行输入和输出的重定向。无法通过以下呼叫完成重定向:
/* Does not work. */
execl("/usr/bin/gzip", "gzip", "-9", "<", filename, ">", zippedFilename, (char *)NULL);
在shell(如bash)中运行命令时,shell会拦截<
和>
,从命令中剥离它们及其后续参数,并在不使用它们的情况下调用实际程序。因此,键入以下内容:
gzip -9 < filename > filename.gz
实际上使shell仅使用一个参数gzip
运行-9
。然后,shell从filename
中读取数据,并将其传递给gzip程序进程的标准输入描述符。同样,shell从相同的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();
对InheritIO()的调用将导致外部进程的标准错误(即所有错误消息)出现在Java程序的标准错误中。否则,您将无法指示程序为何失败。 (如果我们没有重定向它们,则对标准输入和标准输出也一样。)