【问题标题】:Copying entries from ZipInputStream从 ZipInputStream 复制条目
【发布时间】:2018-07-11 12:19:46
【问题描述】:

我可以像这样遍历ZipEntrys 的ZipInputStream

ByteArrayInputStream schema = new ByteArrayInputStream(schemaData);
ZipInputStream zis = new ZipInputStream(schema);
ZipEntry entry;
while((entry = zis.getNextEntry()) != null) {
     String entryName = entry.getName();
     // filter based on entry name
     // how to copy this entry?
}

如何复制此 Zip 文件的某些条目?

【问题讨论】:

    标签: java stream


    【解决方案1】:

    是的,这当然是可能的。当您调用 ZipInputStream.getNextEntry() 时,它会将流定位在下一个数据条目的开头,在这种情况下,您需要的是子 zip 文件中的数据。该流不会超过该数据的末尾,因此不必担心读取下一个条目,ZipInputStream 的条目基本上可以视为它们自己的单个流。

    public static void main(String[] args) throws IOException {
        // ** specify an output directory to copy files to
        final File outDir = new File("path\\to\\...\\OutDir");
    
        // ** read the zip input stream and do for each entry...
        final String pathToZip = "path\\to\\...\\ZipTest.zip";
        try (InputStream is = new FileInputStream(pathToZip);
                ZipInputStream zis = new ZipInputStream(is);) {
    
            forEachZipEntry(zis, (zipEntry, subZipStream) -> {
                // ** specify how to consume each zip entry and stream...
                // ** apply filters here, based on the zip entry
                if (zipEntry.getName().equals("normalZippedDir.zip")) {
                    // ** copy the zip stream to the file
                    File outFile = new File(outDir, zipEntry.getName());
                    try (FileOutputStream fis = new FileOutputStream(outFile);) {
                        // apache IOUtils or whatever copy method you want
                        IOUtils.copy(subZipStream, fis);
                    } catch (IOException e) { e.printStackTrace(); }
                }
            });
        }
    }
    
    /**
     * Iterates through all {@linkplain ZipEntry}s of the given {@linkplain ZipInputStream} and
     * passes the current zip entry and stream to the provided {@linkplain BiConsumer}, but does
     * <b>not</b> recursively parse entries of nested zip files.
     */
    public static void forEachZipEntry(ZipInputStream zis, BiConsumer<ZipEntry, ZipInputStream> consumer)
            throws IOException {
        Objects.requireNonNull(zis);
        Objects.requireNonNull(consumer);
        ZipEntry entry;
        while ((entry = zis.getNextEntry()) != null) {
            consumer.accept(entry, zis);
        }
    }
    
    /**
     * Recursively iterates through <b>all</b> {@linkplain ZipEntry}s <i>(including entries of nested zip
     * files)</i> of the given {@linkplain ZipInputStream} passing the current zip entry and stream to
     * the provided {@linkplain BiConsumer}.
     */
    public static void forEachZipEntryRecursive(ZipInputStream zis,
            BiConsumer<ZipEntry, ZipInputStream> consumer) throws IOException {
        Objects.requireNonNull(zis);
        Objects.requireNonNull(consumer);
        ZipEntry entry;
        while ((entry = zis.getNextEntry()) != null) {
            consumer.accept(entry, zis);
            @SuppressWarnings("resource") // ** caller shall close `zis`
            ZipInputStream subZis = new ZipInputStream(zis);
            forEachZipEntryRecursive(subZis, consumer);
        }
    }
    

    【讨论】:

    • 所以如果我理解正确:如果文件名包含当前条目的 zip,则将所有元素从下一个条目复制到末尾到 subZipInputStream?
    • 该名称并不能保证它是否是 Zip 文件,因此您应该处理异常;但是 .zip.jar 通常是 Zip 文件,除非文件的创建者对文件类型撒谎。一旦你有了你的 sub zip 输入流,你可以用它做任何你喜欢的事情,如果你想复制它的元素然后继续。
    • @Gordon 如果这回答了您的问题,请接受它。
    • 我认为这不能解决我的问题,因为代码正在切割流的左侧并返回右侧,这是一种过滤但不是完全过滤(想象 4 个条目,我想得到第二个和第四个然后这段代码只会给我第四个)
    • @Gordon 切断流的左侧?你运行过这段代码吗?它遍历 Zip 文件的 所有 条目和子条目,并获取每个条目的流。我会让代码真正递归,这样您就不必担心嵌套 zip 文件的深度,但它应该可以工作。
    猜你喜欢
    • 2013-11-30
    • 1970-01-01
    • 1970-01-01
    • 2022-01-14
    • 2023-02-08
    • 2010-09-09
    • 2014-01-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多