5

我正在从事一个处理大量数据的项目。我有很多(数千)个 zip 文件,每个都包含一个包含数千行(约 80k 行)的简单 txt 文件。我目前正在做的事情如下:

for(File zipFile: dir.listFiles()){
ZipFile zf = new ZipFile(zipFile);
ZipEntry ze = (ZipEntry) zf.entries().nextElement();
BufferedReader in = new BufferedReader(new InputStreamReader(zf.getInputStream(ze)));
...

这样我可以逐行读取文件,但是速度太慢了。鉴于需要读取大量文件和行,我需要以更有效的方式读取它们。

我一直在寻找一种不同的方法,但我找不到任何东西。我认为我应该使用的是适用于密集 I/O 操作的 java nio API,但我不知道如何将它们与 zip 文件一起使用。

任何帮助将不胜感激。

谢谢,

马可

4

6 回答 6

3

我有很多(数千)个 zip 文件。压缩文件每个大约 30MB,而 zip 文件中的 txt 大约 60/70 MB。使用此代码读取和处理文件需要花费大量时间,大约 15 小时,但这取决于情况。

让我们做一些粗略的计算。

假设您有 5000 个文件。如果处理它们需要 15 个小时,这相当于每个文件约 10 秒。每个文件大约 30MB,因此吞吐量约为 3MB/s。

这比ZipFile解压速度慢一到两个数量级。

磁盘有问题(它们是本地的,还是网络共享的?),或者是实际处理占用了大部分时间。

最好的确定方法是使用分析器。

于 2012-05-24T15:20:47.053 回答
3

迭代 zip 文件的正确方法

final ZipFile file = new ZipFile( FILE_NAME );
try
{
    final Enumeration<? extends ZipEntry> entries = file.entries();
    while ( entries.hasMoreElements() )
    {
        final ZipEntry entry = entries.nextElement();
        System.out.println( entry.getName() );
        //use entry input stream:
        readInputStream( file.getInputStream( entry ) )
    }
}
finally
{
    file.close();
}

private static int readInputStream( final InputStream is ) throws IOException {
    final byte[] buf = new byte[ 8192 ];
    int read = 0;
    int cntRead;
    while ( ( cntRead = is.read( buf, 0, buf.length ) ) >=0  )
    {
        read += cntRead;
    }
    return read;
}

Zip 文件由几个条目组成,每个条目都有一个字段,其中包含当前条目中的字节数。因此,无需实际数据解压缩即可轻松迭代所有 zip 文件条目。java.util.zip.ZipFile 接受文件/文件名并使用随机访问在文件位置之间跳转。另一方面,java.util.zip.ZipInputStream 正在处理流,因此无法自由跳转。这就是为什么它必须读取和解压缩所有 zip 数据才能到达每个条目的 EOF 并读取下一个条目标题。

这是什么意思?如果您的文件系统中已经有一个 zip 文件 - 无论您的任务如何,都使用 ZipFile 来处理它。作为奖励,您可以按顺序或随机访问 zip 条目(性能损失相当小)。另一方面,如果您正在处理流,则需要使用 ZipInputStream 顺序处理所有条目。

这是一个例子。使用 ZipFile 在 0.05 秒内迭代包含三个 0.6Gb 条目的 zip 存档(总文件大小 = 1.6Gb),使用 ZipInputStream 在 18 秒内迭代。

于 2015-03-29T16:05:19.450 回答
1

您可以像这样使用新的文件 API:

Path jarPath = Paths.get(...);
try (FileSystem jarFS = FileSystems.newFileSystem(jarPath, null)) {
    Path someFileInJarPath = jarFS.getPath("/...");
    try (ReadableByteChannel rbc = Files.newByteChannel(someFileInJarPath, EnumSet.of(StandardOpenOption.READ))) {
        // read file
    }
}

该代码适用于 jar 文件,但我认为它也适用于 zip。

于 2012-05-24T15:19:13.380 回答
0

你可以试试这段代码

try
    {

        final ZipFile zf = new ZipFile("C:/Documents and Settings/satheesh/Desktop/POTL.Zip");

        final Enumeration<? extends ZipEntry> entries = zf.entries();
        ZipInputStream zipInput = null;

        while (entries.hasMoreElements())
        {
            final ZipEntry zipEntry=entries.nextElement();
            final String fileName = zipEntry.getName();
        // zipInput = new ZipInputStream(new FileInputStream(fileName));
            InputStream inputs=zf.getInputStream(zipEntry);
            //  final RandomAccessFile br = new RandomAccessFile(fileName, "r");
                BufferedReader br = new BufferedReader(new InputStreamReader(inputs, "UTF-8"));
                FileWriter fr=new FileWriter(f2);
            BufferedWriter wr=new BufferedWriter(new FileWriter(f2) );

            while((line = br.readLine()) != null)
            {
                wr.write(line);
                System.out.println(line);
                wr.newLine();
                wr.flush();
            }
            br.close();
            zipInput.closeEntry();
        }


    }
    catch(Exception e)
    {
        System.out.print(e);
    }
    finally
    {
        System.out.println("\n\n\nThe had been extracted successfully");

    }

这段代码运行良好。

于 2013-02-11T19:17:38.477 回答
0

英特尔制作了zlib的改进版本,Java 在内部使用它来执行 zip/unzip。它要求您使用 Interl 的IPP补丁修补 zlib 源。我做了一个基准测试,显示吞吐量提高了 1.4 到 3 倍。

于 2017-08-07T06:03:02.110 回答
0

异步解包和同步处理

使用来自Java Performance的建议,这很像来自 Wasim Wani 的答案来自 Satheesh Kumar的建议:迭代 ZIP 条目以获取InputStream它们中的每一个并且他们对它们做一些事情,我构建了自己的解决方案。

在我的情况下,处理是瓶颈,因此我在开始时大规模启动并行提取,迭代entries.hasMoreElements(),并将每个结果放在ConcurrentLinkedQueue我从处理线程中使用的 a 中。我的 ZIP 包含一组表示序列化 Java 对象的 XML 文件,因此我的“提取”包括反序列化对象,而那些反序列化的对象是放在队列中的对象。

对我来说,与我之前从 ZIP 顺序获取每个文件并对其进行处理的方法相比,这有一些优势:

  1. 更引人注目的是:总时间减少 10%
  2. 文件的发布发生得更早
  3. 整个 RAM 分配得更快,所以如果没有足够的 RAM,它会更快地失败(在几十分钟而不是一个多小时内);请注意,我在处理后保留分配的内存量与解压缩文件占用的内存量非常相似,否则最好依次解压缩和丢弃以保持内存占用更低
  4. 解压缩和反序列化似乎有很高的 CPU 使用率,所以完成得越快,你得到 CPU 处理的速度就越快,这才是真正重要的

有一个缺点:当包含并行性时,流控制有点复杂。

于 2019-07-11T10:55:51.287 回答