从包含大量文件的 zip 文件中提取 1 个文件的最快方法是什么?

问题描述 投票:0回答:4

我尝试了java.util.zip包,它太慢了。

然后我找到了 LZMA SDK7z jbinding 但他们也缺少一些东西。

LZMA SDK没有提供一种如何使用的文档/教程,这非常令人沮丧。没有javadoc。

虽然 7z jbinding 不提供仅提取 1 个文件的简单方法,但它仅提供提取 zip 文件的所有内容的方法。而且,它没有提供指定放置解压文件的位置的方法。

请问有什么想法吗?

java unzip compression
4个回答
16
投票

您的

java.util.zip
代码是什么样子的?您正在处理多大的 zip 文件?

我能够在大约一秒钟内从包含 1,800 个条目的 200MB zip 文件中提取 4MB 条目:

OutputStream out = new FileOutputStream("your.file");
FileInputStream fin = new FileInputStream("your.zip");
BufferedInputStream bin = new BufferedInputStream(fin);
ZipInputStream zin = new ZipInputStream(bin);
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
    if (ze.getName().equals("your.file")) {
        byte[] buffer = new byte[8192];
        int len;
        while ((len = zin.read(buffer)) != -1) {
            out.write(buffer, 0, len);
        }
        out.close();
        break;
    }
}

13
投票

我没有对速度进行基准测试,但使用 java 7 或更高版本,我按如下方式提取文件。
我想它比 ZipFile API 更快:

从 zip 文件中提取

META-INF/MANIFEST.MF
的简短示例
test.zip
:

// file to extract from zip file
String file = "MANIFEST.MF";
// location to extract the file to
File outputLocation = new File("D:/temp/", file);
// path to the zip file
Path zipFile = Paths.get("D:/temp/test.zip");

// load zip file as filesystem
try (FileSystem fileSystem = FileSystems.newFileSystem(zipFile)) {
    // copy file from zip file to output location
    Path source = fileSystem.getPath("META-INF/" + file);
    Files.copy(source, outputLocation.toPath());
}

5
投票

使用 ZipFile 而不是 ZipInputStream

虽然文档没有指出这一点(它在

JarFile
的文档中),但它应该使用随机访问文件操作来读取文件。由于 ZIP 文件包含位于已知位置的目录,这意味着查找特定文件所需的 IO 量要少很多。

一些注意事项:据我所知,Sun 实现使用内存映射文件。这意味着您的虚拟地址空间必须足够大才能容纳文件以及 JVM 中的其他所有内容。对于 32 位服务器来说这可能是个问题。另一方面,它可能足够聪明,可以避免在 32 位上进行内存映射,或者仅对目录进行内存映射;我没试过。

此外,如果您使用多个文件,请务必使用

try
/
finally
以确保文件在使用后关闭。


0
投票

假设您知道目标 zip 文件路径和目标条目文件名, 下面的代码片段是一个示例,它在大约 11 毫秒内从 zip 中读取大约 340KB 的 protobuf 二进制文件。

无需遍历文件,因为 ZipFile 接口提供了直接获取条目的方法。

   public <T extends Message> Message readMessageFromZip(final Path zipPath, 
                                                         final String entryName, 
                                                         final Parser<T> messageParser) 
                                                         throws IOException {
        try (ZipFile zipFile = new ZipFile(zipPath.toFile()))
        {
            ZipEntry zipEntry = zipFile.getEntry(entryName);
            return messageParser.parseFrom(zipFile.getInputStream(zipEntry));
        }
    }

© www.soinside.com 2019 - 2024. All rights reserved.