在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("\n\n\nThe had been extracted successfully"); }
这段代码工作得很好。
英特尔已经改进了zlib版本,Java使用内部peroform zip / unzip。 它要求您使用Interl的IPP缓存来修补zlib源。 我做了一个基准测试,显示吞吐量增加了1.4倍到3倍。