代码之家  ›  专栏  ›  技术社区  ›  Aditya

使用Puff生机时Java没有启动GZIP命令

  •  0
  • Aditya  · 技术社区  · 6 年前

    我肯定有 GZIP 安装在我尝试这个的盒子上。但是当我在Java中运行时,我看不到正在创建的压缩文件。我正在处理的文件是一个非常大的文件,我不想把它读到内存中。以下是我为此编写的代码。我的预感是它与重定向有关。

    try {
        ProcessBuilder builder = new ProcessBuilder("gzip", "-9", "<", filename, ">", zippedFilename);
        builder.start();
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   VGR    6 年前

    首先,值得注意的是,您可以通过避免外部过程和使用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,不需要在Windows上使用Unix工具。它不会实现 -9 选项,但我将检查使用该选项实际获得的额外压缩量,并权衡使用不太便携的程序是否值得。

    对于其他命令(或如果 - 9 非常重要),processbuilder命令不能使用 < > ,同样的原因,C程序无法通过如下调用完成重定向:

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

    在shell(如bash)中运行命令时,shell会截取 < > ,从命令中剥离它们及其后续参数,并在没有它们的情况下调用实际程序。因此,输入:

    gzip -9 < filename > filename.gz
    

    实际上导致shell运行 gzip 只有一个论点: - 9 . 然后外壳读取 filename 并将其传递给gzip程序的标准输入描述符。同样,shell从相同的gzip程序调用中捕获标准输出,并将其写入 filename.gz .

    在这过程中,gzip进程不知道其输入来自何处,也不知道其输出将流向何处。它只是从自己的标准输入中读取数据,并写入到自己的标准输出中。

    当您直接调用一个程序时,您将绕过shell,因此没有对 < > . 这意味着您当前的processbuilder命令与此unix命令等效:

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

    这意味着您正在使用一个选项和四个文件参数调用gzip,这将导致gzip首先查找一个文件,该文件的名称为一个字符长,文件的字面名称为 < ,然后将其压缩版本写入 <.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程序的标准错误上。如果没有这一点,您将无法知道程序失败的原因。(如果我们没有重新定向标准输入和标准输出,它也可以这样做。)