Java 从ZipInputStream复制条目

Java 从ZipInputStream复制条目,java,stream,Java,Stream,我能够像这样迭代ZipInputStream的ZipEntrys: ByteArrayInputStream schema = new ByteArrayInputStream(schemaData); ZipInputStream zis = new ZipInputStream(schema); ZipEntry entry; while((entry = zis.getNextEntry()) != null) { String entryName = entry.getName

我能够像这样迭代
ZipInputStream
ZipEntry
s:

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文件的某些条目?

是的,这当然是可能的。调用时,将流定位在下一个数据项的开头,在本例中,当数据是子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);
    }
}
publicstaticvoidmain(字符串[]args)引发IOException{
//**指定要将文件复制到的输出目录
最终文件outDir=新文件(“路径\\到\\…\\outDir”);
//**读取zip输入流并对每个条目执行操作。。。
最后一个字符串pathToZip=“path\\to\\…\\ZipTest.zip”;
try(InputStream=newfileinputstream(pathToZip);
ZipInputStream zis=新ZipInputStream(is);){
forEachZipEntry(zis,(zipEntry,subZipStream)->{
//**指定如何使用每个zip条目和流。。。
//**根据zip条目在此处应用过滤器
if(zipEntry.getName().equals(“normalZippedDir.zip”)){
//**将压缩流复制到文件中
File outFile=新文件(outDir,zipEntry.getName());
try(FileOutputStream fis=newfileoutputstream(outFile);){
//apacheioutils或任何您想要的复制方法
IOUtils.副本(子流,fis);
}catch(IOE异常){e.printStackTrace();}
}
});
}
}
/**
*迭代给定{@linkplain ZipInputStream}的所有{@linkplain ZipEntry},并
*将当前zip条目和流传递给提供的{@linkplain BiConsumer},但不传递
*不递归分析嵌套zip文件的条目。
*/
公共静态无效forEachZipEntry(ZipInputStream zis,双消费者)
抛出IOException{
对象。requirennull(zis);
对象。requirennull(消费者);
ZipEntry入口;
而((entry=zis.getNextEntry())!=null){
消费者。接受(输入,zis);
}
}
/**
*递归地迭代所有{@linkplain ZipEntry}(包括嵌套zip的条目
*将当前zip条目和流传递给
*提供的{@linkplain BiConsumer}。
*/
公共静态无效forEachZipEntryRecursive(ZipInputStream zis,
双消费者(消费者)抛出IOException{
对象。requirennull(zis);
对象。requirennull(消费者);
ZipEntry入口;
而((entry=zis.getNextEntry())!=null){
消费者。接受(输入,zis);
@SuppressWarnings(“资源”)/**调用者应关闭'zis'`
ZipInputStream subZis=新的ZipInputStream(zis);
forEachZipEntryRecursive(subZis,consumer);
}
}

因此,如果我理解正确:如果文件名包含当前条目的zip,则将下一个条目的所有元素复制到subZipInputStream的末尾?该名称不能保证它是否为zip文件,因此您应该处理异常;然而,
.zip
.jar
通常是zip文件,除非文件的创建者对其文件类型撒谎。一旦你有了sub-zip输入流,你可以用它做任何你想做的事情,如果你想复制它的元素,那就继续吧。@Gordon如果这回答了你的问题,请接受它。我不认为这解决了我的问题,因为代码正在剪切流的左侧,并返回右侧,这是一种过滤,但不是完全过滤(假设有4个条目,我想得到第二个和第四个条目,那么这个代码只会得到第四个条目)@Gordon切割流的左侧?您运行过此代码吗?它正在迭代Zip文件的所有条目和子条目,并获取每个条目的流。我将使代码实际上是递归的,这样您就不必担心嵌套Zip文件的深度,但实际上它应该可以工作。