【问题标题】:Zipping Folder with Java but Excluding Certain Sub-directories使用 Java 压缩文件夹但不包括某些子目录
【发布时间】:2017-05-28 17:38:15
【问题描述】:

我设法找到了两个使用 Java 压缩目录的示例 sn-ps 代码:

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 中。

有人可以帮我吗?

非常感谢!

【问题讨论】:

    标签: java zip directory


    【解决方案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 引用的原始文件遍历器代码会导致包含错误的工件。这是由于ZipEntry 路径的“相对化”。 SimpleFileVistor 中的路径不应调整。如果需要存档是相对的或 绝对的,那么原来的srcPath就应该这样设置。

    【讨论】:

    • 能否提供一些示例代码?这对我来说意味着整个世界!
    • 我会看看我能做什么。
    • 我测试了上面的代码,但不是只排除文件夹中指定的子目录,而是排除所有内容。
    • 我自己也测试了它——在发布之前——它似乎有效,但我不保证你找到的代码的质量。您是否在未指定任何排除项的情况下尝试了测试用例以确保您的路径正确?在访问方法中撒上几个println,看看他们正在触及哪些路径。再说一次,这样做的目的是举例说明如何在文件树遍历中排除目录,而不是编写 zip 实用程序。正如我所说,它的演示代码。我把你送到门口。你必须走过它:)
    • 我想我找到了问题 - 必须按照您原来的建议将 FileVisitResult.SKIP_SIBLINGS 更改为 FileVisitResult.SKIP_SUBTREE。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2011-12-31
    • 2013-02-13
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多