在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文件的主要内容,如果未能解决你的问题,请参考以下文章