使用Java压缩文件夹但不包括某些子目录

时间:2017-01-13 11:01:16

标签: java zip directory

我设法找到两个使用Java压缩目录的代码片段:

public static void pack(final Path folder, final Path zipFilePath) throws IOException {
    try (
            FileOutputStream fos = new FileOutputStream(zipFilePath.toFile());
            ZipOutputStream zos = new ZipOutputStream(fos)
    ) {
        Files.walkFileTree(folder, new SimpleFileVisitor<Path>() {
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                zos.putNextEntry(new ZipEntry(folder.relativize(file).toString()));
                Files.copy(file, zos);
                zos.closeEntry();
                return FileVisitResult.CONTINUE;
            }

            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                zos.putNextEntry(new ZipEntry(folder.relativize(dir).toString() + "/"));
                zos.closeEntry();
                return FileVisitResult.CONTINUE;
            }
        });
    }
}

public static void pack(String sourceDirPath, String zipFilePath) throws IOException {
    Path p = Files.createFile(Paths.get(zipFilePath));
    try (ZipOutputStream zs = new ZipOutputStream(Files.newOutputStream(p))) {
        Path pp = Paths.get(sourceDirPath);
        Files.walk(pp)
          .filter(path -> !Files.isDirectory(path))
          .forEach(path -> {
              ZipEntry zipEntry = new ZipEntry(pp.relativize(path).toString());
              try {
                  zs.putNextEntry(zipEntry);
                  zs.write(Files.readAllBytes(path));
                  zs.closeEntry();
            } catch (Exception e) {
                System.err.println(e);
            }
          });
    }
}

但是,对于这两个例子,我无法解释如何排除源目录中的某些子目录被包含在输出zip中。

有人可以伸出援手吗?

非常感谢你!

1 个答案:

答案 0 :(得分:1)

简短的回答是在preVisitDirectory(...)方法中定义目录过滤器,以便在它预先访问您要排除的目录时返回FileVisitResult.SKIP_SUBTREE

有关详情,请参阅Walking the File Tree控制流程部分。

修改

根据要求,使用上面提供的代码进行示例实现。使用指向源目录(srcPath)和Zip文件名(zipPath)的路径创建它的实例。添加要排除的任何目录名称。例如,addDirExclude( "bin" )将排除任何名为bin的目录,其文件以及其下的任何子目录。

这是一个示例,旨在演示进一步控制文件树遍历的几种方法之一。 这不是生产质量代码;使用风险自负。

public class ZipWithExcludedDirs {
    final private Path         srcPath;
    final private Path         zipPath;
    final private List<String> excludeList = new ArrayList<>();


    public ZipWithExcludedDirs( Path srcPath, Path zipPath ) {
        this.srcPath = srcPath;
        this.zipPath = zipPath;
    }


    public void addDirExclude( String exDir ) {
        excludeList.add( exDir );
    }


    public void pack() throws IOException {
        try ( FileOutputStream fos = new FileOutputStream( zipPath.toFile() );
                ZipOutputStream zos = new ZipOutputStream( fos ) ) {
            Files.walkFileTree( srcPath, new SimpleFileVisitor<Path>() {
                public FileVisitResult visitFile( Path file, BasicFileAttributes attrs )
                        throws IOException {
                    zos.putNextEntry( new ZipEntry( file.toString() ) );
                    Files.copy( file, zos );
                    zos.closeEntry();
                    return FileVisitResult.CONTINUE;
                }


                public FileVisitResult preVisitDirectory( Path dir, BasicFileAttributes attrs )
                        throws IOException {
                    String dirName = dir.getFileName().toString();
                    for ( String excl : excludeList )
                        if ( dirName.equals( excl ) )
                            return FileVisitResult.SKIP_SUBTREE;

                    zos.putNextEntry( new ZipEntry( dir.toString() + "/" ) );
                    zos.closeEntry();
                    return FileVisitResult.CONTINUE;
                }
            } );
        }
    }
}

编辑(部分Deux)

我已经编辑了上面的代码,以便它返回SKIP_SUBTREE而不是SKIP_SIBLINGS,这是我原来的,但由于某种原因而改变了。一瞥JavaDocs似乎表明SKIP_SUBTREESKIP_SIBLINGS对所访问的目录具有相同的效果。确实如此。但是SKIP_SIBLINGS也会影响目录的兄弟(即在同一父目录中跟随它的文件和目录)。

此外,OP引用的原始文件walker代码会导致包含错误的工件。这是由于ZipEntry路径的“相对化”。路径不应在SimpleFileVistor中调整。如果存档需要相对或 绝对,然后原始srcPath应该这样设置。