在Java中有效地读取zip文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Java中有效地读取zip文件相关的知识,希望对你有一定的参考价值。

我正在开发一个可以处理大量数据的项目。我有很多(数千)zip文件,每个文件包含一个简单的txt文件,包含数千行(大约80k行)。我目前正在做的是以下内容:

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文件一起使用。

真的很感激任何帮助。

谢谢,

骨架

答案

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

让我们做一些背后的计算。

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

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

磁盘是否存在问题(它们是本地磁盘还是网络共享?),或者是大部分时间都在进行的实际处理。

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

另一答案

迭代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秒内迭代。

另一答案

您可以像这样使用新文件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文件,但我认为它也适用于拉链。

另一答案

您可以尝试此代码

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("


The had been extracted successfully");

    }

这段代码工作得很好。

另一答案

英特尔已经改进了zlib版本,Java使用内部peroform zip / unzip。它要求您使用Interl的IPP paches修补zlib源。我做了一个benchmark,吞吐量增加1.4倍到3倍。

以上是关于在Java中有效地读取zip文件的主要内容,如果未能解决你的问题,请参考以下文章

java 如何读取本地硬盘上面的zip文件. 返回ZipInputStream流!

直接读取 Zip 文件中的文件 - Java

在 Haskell 中有效地读取和排序包含文本行的文件

java怎么读取Zip和RAR里面的文件啊?

无法读取所需库的存档或不是有效的 ZIP 文件

java怎么读取Zip和RAR里面的文件啊?