简体   繁体   English

使用ProcessBuilder时Java不启动GZIP命令

[英]Java is not launching GZIP command when using ProcessBuilder

I definitely have GZIP installed on the boxes where I am trying this out. 我肯定在尝试此操作的盒子上安装了GZIP But when I run this in Java, I don't see the zipped file being created. 但是,当我在Java中运行此文件时,看不到正在创建的压缩文件。 The file I am dealing with is a really large file and I would rather not read it into memory. 我正在处理的文件是非常大的文件,因此我不希望将其读入内存。 The following is the code, I have written for this purpose. 以下是我为此编写的代码。 My hunch is that it has something to do with Redirects. 我的直觉是它与重定向有关。

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

First, it's worth noting that you can make this easier by avoiding an external process and using Java to do the compression: 首先,值得注意的是,您可以通过避免使用外部进程并使用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);
}

This has the additional advantage of being fully multi-platform. 这具有完全多平台的额外优势。 No need to require /usr/bin/gzip, no need to require Unix tools on Windows. 在Windows上不需要/ usr / bin / gzip,也不需要Unix工具。 It won't implement the -9 option, but I would check how much additional compression one actually gets with that option, and weigh whether it's worth having a less portable program. 它不会实现-9选项,但我将检查该选项实际获得了多少额外的压缩,并权衡是否值得拥有一个便携式性较低的程序。

For other commands (or if -9 is critically important), a ProcessBuilder command cannot do redirection of input and output with < and > , for the same reason a C program would not be able to accomplish redirection with a call like: 对于其他命令(或-9非常重要),ProcessBuilder命令无法使用<>进行输入和输出的重定向,出于相同的原因,C程序将无法通过以下调用来完成重定向:

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

When you run a command in a shell (like bash), the shell intercepts < and > , strips them and their subsequent arguments from the command, and invokes the actual program without them. 在外壳程序(如bash)中运行命令时,外壳程序会截取<> ,从命令中剥离它们和它们的后续参数,并在不使用它们的情况下调用实际程序。 Thus, typing this: 因此,键入以下内容:

gzip -9 < filename > filename.gz

actually causes the shell to run gzip with just one argument: -9 . 实际上导致外壳运行gzip仅带有一个参数: -9 The shell then reads from filename and passes it to the standard input descriptor of the gzip program's process. 然后,shell从filename读取并将其传递给gzip程序进程的标准输入描述符。 Similarly, the shell captures the standard output from that same gzip program invocation, and writes it to filename.gz . 类似地,shell从相同的gzip程序调用中捕获标准输出,并将其写入filename.gz

While this is going on, the gzip process has no idea where its input came from, or where its output is going. 在此过程中,gzip进程不知道其输入来自何处或其输出在何处。 It is just reading from its own standard input and writing to its standard output. 它只是从自己的标准输入读取并写入其标准输出。

When you invoke a program directly, you are bypassing the shell, so there is no special handling of < and > . 直接调用程序时,将绕过外壳程序,因此对<>没有特殊处理。 This means that your current ProcessBuilder command is the equivalent of this Unix command: 这意味着您当前的ProcessBuilder命令与此Unix命令等效:

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

which means you are invoking gzip with one option and four file arguments, which cause gzip to first look for a file whose name is one character long, a file literally named < , then write a compressed version of it to <.gz . 这意味着您要调用带有一个选项和四个文件参数的gzip,这将导致gzip首先查找名称为一个字符长的文件,一个字面名为<的文件,然后将其压缩版本写入<.gz It will then do the same with a file named filename , then a file named > , then a file named filename.gz . 然后,它将对名为filename ,然后对名为>的文件,对文件名filename.gz

So, as you can see, Unix commands know nothing about redirection. 因此,如您所见,Unix命令对重定向一无所知。 The < and > characters cannot be passed to them directly. <>字符不能直接传递给它们。

However, you can simulate redirection using ProcessBuilder: 但是,您可以使用ProcessBuilder模拟重定向:

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

Process process = builder.start();

The call to inheritIO() will cause the external process's standard error (that is, any error messages) to appear on the Java program's standard error. 对InheritIO()的调用将导致外部进程的标准错误(即,任何错误消息)出现在Java程序的标准错误上。 Without that, you would have no indication of why the program failed. 否则,您将无法指示程序为何失败。 (It would do the same with standard input and standard output, if we hadn't redirected them.) (如果我们没有重定向它们,它将对标准输入和标准输出执行相同的操作。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM