使用java 8的stream api列出zip文件中的条目-亚博电竞手机版
java 8中的java.util.zip.zipfile
包中提供了stream
方法,能够非常容易的获取zip压缩包中的条目。在这篇文章中,我会通过一系列的示例来展示我们可以非常快速的遍历zip文件中的条目。
注意:为了在这篇博客中做演示,我从github上以zip文件的形式下载了我的一个项目,放在了c:/tmp
目录下。
java7之前的做法
在java7之前,读取一个zip文件中的条目的做法,恩……需要一点点小技巧。当你看到下面的代码的时候,大概就会开始有点讨厌java了。
public class zipper { public void printentries(printstream stream, string zip) { zipfile zipfile = null; try { zipfile = new zipfile(zip); enumeration entries = zipfile.entries(); while (entries.hasmoreelements()) { zipentry zipentry = entries.nextelement(); stream.println(zipentry.getname()); } } catch (ioexception e) { // error while opening a zip file } finally { if (zipfile != null) { try { zipfile.close(); } catch (ioexception e) { // do something } } } } }
java 7的做法
多谢有了try-with-resources
这样新的try代码块的写法,在java 7中的代码变得稍微好了一些,但我们还是被“强迫”来使用enumeration
来遍历zip压缩包中的条目:
public class zipper { public void printentries(printstream stream, string zip) { try (zipfile zipfile = new zipfile(zip)) { enumeration entries = zipfile.entries(); while (entries.hasmoreelements()) { zipentry zipentry = entries.nextelement(); stream.println(zipentry.getname()); } } catch (ioexception e) { // error while opening a zip file } } }
使用strean api
真正有意思的是从java 8开始,java 8提供在java.util.zip.zipfile
包中提供新的stream
方法,能够返回zip压缩包中的条目的有序的流,使得java在处理zip压缩包时有了更多的选择。前文提到的读取压缩包的条目的代码可以改写成如下简单的形式:
public class zipper { public void printentries(printstream stream, string zip) { try (zipfile zipfile = new zipfile(zip)) { zipfile.stream() .foreach(stream::println); } catch (ioexception e) { // error while opening a zip file } } }
如下文所示,有了stream api,我们有了更多更有趣的方式来处理zip文件。
对zip压缩包的内容进行过滤和排序
public void printentries(printstream stream, string zip) { try (zipfile zipfile = new zipfile(zip)) { predicateisfile = ze -> !ze.isdirectory(); predicate isjava = ze -> ze.getname().matches(".*java"); comparator bysize = (ze1, ze2) -> long.valueof(ze2.getsize() - ze1.getsize()).intvalue(); zipfile.stream() .filter(isfile.and(isjava)) .sorted(bysize) .foreach(ze -> print(stream, ze)); } catch (ioexception e) { // error while opening a zip file } } private void print(printstream stream, zipentry zipentry) { stream.println(zipentry.getname() ", size = " zipentry.getsize()); }
在迭代zip压缩包的条目时,我检查了这个条目是否是一个文件并且是否匹配一个给定的字段(为了简单,直接把匹配字段硬编码在代码中了),然后利用一个给定的比较器,对这些条目按照大小进行了排序。
为zip压缩包创建文件索引
在这个例子中,我把zip压缩包中的条目按照文件名的首字母分组,建立形如map
的索引,预想的结果应该看起来像这样简单:
a = [somefile/starting/with/an/a] u = [somefile/starting/with/an/u, someotherfile/starting/with/an/u]
同样,使用stream api来实现这个功能非常简单:
public void printentries(printstream stream, string zip) { try (zipfile zipfile = new zipfile(zip)) { predicateisfile = ze -> !ze.isdirectory(); predicate isjava = ze -> ze.getname().matches(".*java"); comparator bysize = (ze1, ze2) -> long.valueof(ze2.getsize()).compareto(long.valueof(ze1.getsize())); map > result = zipfile.stream() .filter(isfile.and(isjava)) .sorted(bysize) .collect(groupingby(this::fileindex)); result.entryset().stream().foreach(stream::println); } catch (ioexception e) { // error while opening a zip file } } private string fileindex(zipentry zipentry) { path path = paths.get(zipentry.getname()); path filename = path.getfilename(); return filename.tostring().substring(0, 1).tolowercase(); }
在zip压缩包的文件中查找字段
在这最后一个例子中,我在压缩包中的查找所有以.java
结尾的且包含@test
字段的文件,这次,我将利用bufferedreader
类的lines
方法来实现,这个lines
方法按行返回文件流。
public void printentries(printstream stream, string zip) { try (zipfile zipfile = new zipfile(zip)) { predicateisfile = ze -> !ze.isdirectory(); predicate isjava = ze -> ze.getname().matches(".*java"); list result = zipfile.stream() .filter(isfile.and(isjava)) .filter(ze -> containstext(zipfile, ze, "@test")) .collect(collectors.tolist()); result.foreach(stream::println); } catch (ioexception e) { // error while opening a zip file } } private boolean containstext(zipfile zipfile, zipentry zipentry, string needle) { try (inputstream inputstream = zipfile.getinputstream(zipentry); bufferedreader reader = new bufferedreader(new inputstreamreader(inputstream))) { optional found = reader.lines() .filter(l -> l.contains(needle)) .findfirst(); return found.ispresent(); } catch (ioexception e) { return false; } }
总结
在我看来,stream api提供了一个强大的
并且相对更容易的
方案来解决遍历zip压缩包中的条目的问题。
本文中出现的例子只是用来演示说明stream api的用法的,都是相对容易的,但我希望你能够喜欢这些例子,并且觉得他对你有用。