在Java 8中使用Stream API列出ZIP文件的内容

在Java 8 java.util.zip.ZipFile配备了stream方法,该方法可以非常轻松地浏览ZIP文件条目。 在此博客文章中,我将展示许多示例,这些示例显示了我们可以如何快速浏览ZIP文件条目。

注意:就本博客而言,我将一个GitHub存储库下载为ZIP文件,并将其复制到c:/tmp

Java 7之前的版本

在Java 7之前的Java中读取ZIP文件条目有点麻烦……难道是吗? 这是在查看以下代码时开始讨厌Java的方式:

public class Zipper {
    public void printEntries(PrintStream stream, String zip)  {
        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(zip);
            Enumeration<? extends ZipEntry> 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

使用Java 7,这可以简单得多–感谢try-with-resources但是我们仍然被“强制”使用Enumeration来浏览ZIP文件条目:

public class Zipper {
    public void printEntries(PrintStream stream, String zip) {
        try (ZipFile zipFile = new ZipFile(zip)) {
            Enumeration<? extends ZipEntry> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry zipEntry = entries.nextElement();
                stream.println(zipEntry.getName());
            }
        } catch (IOException e) {
            // error while opening a ZIP file
        }
    }
}

使用流API

真正的乐趣始于Java8。从Java 8开始, java.util.zip.ZipFile具有一个新的方法stream ,该方法流通过ZIP文件条目返回有序流。 在使用Java处理ZIP文件时,这提供了很多机会。 前面的示例可以用Java 8如下编写:

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,我们可以通过多种方式ZipFile 。 见下文…

过滤和排序ZIP文件内容

public void printEntries(PrintStream stream, String zip) {
    try (ZipFile zipFile = new ZipFile(zip)) {
        Predicate<ZipEntry> isFile = ze -> !ze.isDirectory();
        Predicate<ZipEntry> isJava = ze -> ze.getName().matches(".*java");
        Comparator<ZipEntry> 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<String, List<ZipEntry>>索引。 预期结果应类似于以下内容:

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)) {
        Predicate<ZipEntry> isFile = ze -> !ze.isDirectory();
        Predicate<ZipEntry> isJava = ze -> ze.getName().matches(".*java");
        Comparator<ZipEntry> bySize =
            (ze1, ze2) -> Long.valueOf(ze2.getSize()).compareTo(Long.valueOf(ze1.getSize()));

        Map<String, List<ZipEntry>> 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文本出现的地方。 这次,我将利用BufferedReaderlines方法返回行流。

public void printEntries(PrintStream stream, String zip) {

    try (ZipFile zipFile = new ZipFile(zip)) {
        Predicate<ZipEntry> isFile = ze -> !ze.isDirectory();
        Predicate<ZipEntry> isJava = ze -> ze.getName().matches(".*java");

        List<ZipEntry> 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<String> found = reader.lines()
                .filter(l -> l.contains(needle))
                .findFirst();

        return found.isPresent();

    } catch (IOException e) {
        return false;
    }
}

摘要

Java 8中的Stream API是一种功能强大的解决方案,可帮助轻松解决相对简单的任务。 我认为这就是它的力量。

本文中提供的示例相对简单,它们仅为可视化目的而创建。 但我希望您喜欢它们并发现它们有用。

资源资源

翻译自: https://www.javacodegeeks.com/2014/06/listing-a-zip-file-contents-with-stream-api-in-java-8.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值