【问题标题】:Working with Zip and GZip files in Java在 Java 中处理 Zip 和 GZip 文件
【发布时间】:2010-09-14 17:18:04
【问题描述】:

自从我完成 Java I/O 以来已经有一段时间了,我不知道使用 Zip 和 GZip 文件的最新“正确”方法。我不一定需要完整的工作演示——我主要是在寻找要使用的正确接口和方法。是的,我可以查找任何关于此的随机教程,但性能是一个问题(这些文件可能会变得非常大),我确实关心使用最好的工具来完成这项工作。

我将要实现的基本流程:

  • 将一堆文件(可能经过压缩、gzip 压缩或两者兼有)下载到临时文件夹。
  • 将所有提取的文件添加到临时文件夹中的新 zip 文件中。

输入文件可能会被多次压缩和归档。例如,“完全提取”应该采用以下任何输入(我无法控制这些),并留下foo.txt

  • foo.txt.gz
  • foo.txt.zip
  • foo.txt.gz.zip
  • foo.txt.zip.gz
  • ...
  • foo.txt.gz.gz.gz.zip.gz.zip.zip.gz.gz
  • ...

然后,我可能会留下foo.txtbar.mp3baz.exe - 所以我只需将它们全部添加到一个具有通用名称的新 zip 文件中。

问题:

  • 由于文件大小是一个潜在问题,我应该快速使用哪个(接口/类/方法):
    • 解压 zip 文件?
    • 解压 gzip 文件?
    • 写 zip 文件?
  • 在写回磁盘之前,我是否最好将各个提取的文件保存在内存中?或者,
  • 潜在的大文件是否会成为一个坏主意?

【问题讨论】:

    标签: java file-io zip gzip


    【解决方案1】:

    不要将所有这些未压缩的数据保存在内存中,否则您可能会用完堆空间。您需要在解压缩时将数据流式传输到文件中,然后在您想要创建最终 zip 文件时将其从文件中流式传输回。

    我之前没有做过压缩文件,但这里有一个例子说明如何解压缩 gzipped 文件:

    import java.io.*;
    import java.util.zip.*;
    
    //unzipping a gzipped file
    GZIPInputStream in = null;
    OutputStream out = null;
    try {
       in = new GZIPInputStream(new FileInputStream("file.txt.gz"));
       out = new FileOutputStream("file.txt");
       byte[] buf = new byte[1024 * 4];
       int len;
       while ((len = in.read(buf)) > 0) {
           out.write(buf, 0, len);
       }
    }
    catch (IOException e) {
       e.printStackTrace();
    }
    finally {
       if (in != null)
           try {
               in.close();
           }
           catch (IOException ignore) {
           }
       if (out != null)
           try {
               out.close();
           }
           catch (IOException ignore) {
           }
    }
    

    【讨论】:

    • @StanislavPalatnik 可能导致部分代码对问题没有太大影响;)(顺便说一句,我不是反对者)catch (IOException e) { e.printStackTrace(); } 最后 { if (in != null) try { in.close(); } catch (IOException 忽略) { } if (out != null) try { out.close(); } 捕捉(IOException 忽略){ } }
    • 使用 Java 9 可以简化为 try (InputStream in = new GZIPInputStream(new FileInputStream("file.txt.gz")); OutputStream out = new FileOutputStream("file.txt")) { in.transferTo(out); }
    【解决方案2】:

    请注意,下面建议的库 TrueZip 已被 TrueVFS. 取代


    我发现TrueZIP library 很有用。它允许您将归档文件视为只是另一个文件系统,并使用熟悉的 Java I/O API。

    java.util.zip API 不同,TrueZIP 提供对存档内容的随机访问,因此文件大小不应成为问题。如果我没记错的话,它会检测存档文件,并且在您将它们放入存档时不会尝试对其进行冗余压缩。

    引用 TrueZIP 页面:

    TrueZIP API 为知名类 FileFileInputStreamFileOutputStream 提供了替代品。这种设计使 TrueZIP 使用起来非常简单:为大多数客户端应用程序启用归档所需的只是为包 de.schlichtherle.io 添加一些导入语句,并在需要时添加一些类型转换。

    现在您可以简单地处理归档文件,例如路径名中的目录。例如,路径名 "archive.zip/readme" 寻址 ZIP 文件 archive.zip 中的归档条目 readme。请注意,文件名后缀是完全可配置的,TrueZIP 会自动检测误报并恢复为将它们视为普通文件或目录。这是递归的,所以一个存档文件甚至可以包含在另一个存档文件中,比如outer.zip/inner.zip/readme

    【讨论】:

    【解决方案3】:

    在某个地方可能有一个库可以让这变得简单。

    但是,如果没有,您仍然可以使用java.util.zip classes... 使用ZipFileZipInputStream 以及ZipEntry 进行压缩。

    GZIPInputStream 可以为 gzip 包装 FileInputStream,请记住 gzip 仅适用于单个文件。

    这两种类型的 InputStreams 也有各自的 OutputStreams。

    不幸的是,虽然我知道这些类,但我从未真正使用过它们,因此我无法为您提供更多建议。

    编辑:Zip 函数似乎没有任何方法可以在不重新创建整个内容的情况下将新文件添加到 zip 文件中。

    【讨论】:

      猜你喜欢
      • 2020-08-25
      • 1970-01-01
      • 1970-01-01
      • 2011-07-18
      • 1970-01-01
      • 2017-03-22
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      相关资源
      最近更新 更多