ZipInputStream - 解压缩文件的功能方法

ZipInputStream - functional approach to unzip files

我有一个只包含文件而不包含目录的 zip 文件。我想仅使用功能 Java.

将文件解压缩到目录中

下面的代码按预期工作并将文件解压缩到目标文件夹中。

public static void unzip(Path source, Path target) throws IOException {

    try (ZipInputStream zis = new ZipInputStream(new FileInputStream(source.toFile()))) {

        ZipEntry zipEntry = zis.getNextEntry();

        while (zipEntry != null) {

            Path targetDirResolved = target.resolve(zipEntry.getName());

            Path normalizePath = targetDirResolved.normalize();
            if (!normalizePath.startsWith(target)) {
                throw new IOException("Bad zip entry: " + zipEntry.getName());
            }

            Files.copy(zis, normalizePath, StandardCopyOption.REPLACE_EXISTING);

            zipEntry = zis.getNextEntry();

        }
        zis.closeEntry();

    }
}

我想实现与上面相同的功能,但使用更实用的方法。

我最初的想法是将 while 循环转换成类似 IntStream.range(0, ).... 的东西,但不知道 zip 文件中的条目数。

有什么想法吗?

消除 while 循环的一种方法是使用 ZipFilestream:

try (ZipFile fs = new ZipFile(source.toFile())) {
    fs.stream()
      .filter(Predicate.not(ZipEntry::isDirectory))
      // etc
      .forEach(System.out::println);
}

您还可以查看带有 Files.find 的 ZIP 文件系统,以提供合适的 Stream ZIP 条目(一级文件),如果需要,在流而不是 forEach,如下所示:

try (FileSystem fs = FileSystems.newFileSystem(source)) {
    for (Path root : fs.getRootDirectories()) {
        try (Stream<Path> stream = Files.find(root, 1, (p,a) -> a.isRegularFile())) {
            stream.forEach(p -> copy(p, Path.of(target.toString(), p.toString())));
        }
    }
}

不幸的是,上面仍然对根目录使用正常循环,copy 是处理 IOException:

的单独方法
private static void copy(Path from, Path to) {
    try {
        Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING);
    }
    catch (IOException e) {
        throw new UncheckedIOException(e);
    }
}