在 Java 中使用 Zip 和 GZip 文件

2022-09-03 01:38:34

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

我将实现的基本过程:

  • 将一堆文件(可能被压缩、g压缩或两者)下载到临时文件夹。
  • 将所有提取的文件添加到临时文件夹中的新 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
  • ...

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

问题:

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

答案 1

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

我以前没有做过压缩文件,但这里有一个例子,展示了如何解压缩gzi压缩文件:

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) {
       }
}

答案 2

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


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

与API不同,TrueZIP提供对存档内容的随机访问,因此文件大小不应该是一个问题。如果我没记错的话,它会检测存档文件,而不是在将它们放入存档时尝试冗余压缩它们。java.util.zip

引用 TrueZIP 页面:

TrueZIP API 为众所周知的类 和 提供了直接替换。这种设计使 TrueZIP 非常易于使用:大多数客户端应用程序需要为包添加一些 import 语句,并在需要时添加一些类型转换。FileFileInputStreamFileOutputStreamde.schlichtherle.io

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