使用 ZipFileSystem 压缩一个巨大的文件夹会导致 OutOfMemoryError
该软件包通过将zip文件视为文件系统来处理它们。具有处理zip文件的美丽方式。这使我们能够像处理普通文件一样处理zip文件内容。因此,只需将所有文件复制到zip文件中,即可实现压缩整个文件夹。由于子文件夹也需要复制,因此我们需要一个访问者:java.nio
Files.copy
private static class CopyFileVisitor extends SimpleFileVisitor<Path> {
private final Path targetPath;
private Path sourcePath = null;
public CopyFileVisitor(Path targetPath) {
this.targetPath = targetPath;
}
@Override
public FileVisitResult preVisitDirectory(final Path dir,
final BasicFileAttributes attrs) throws IOException {
if (sourcePath == null) {
sourcePath = dir;
} else {
Files.createDirectories(targetPath.resolve(sourcePath
.relativize(dir).toString()));
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(final Path file,
final BasicFileAttributes attrs) throws IOException {
Files.copy(file,
targetPath.resolve(sourcePath.relativize(file).toString()), StandardCopyOption.REPLACE_EXISTING);
return FileVisitResult.CONTINUE;
}
}
这是一个简单的“递归复制目录”访问者。它用于以递归方式复制目录。但是,使用 ,我们也可以使用它将目录复制到 zip 文件中,如下所示:ZipFileSystem
public static void zipFolder(Path zipFile, Path sourceDir) throws ZipException, IOException
{
// Initialize the Zip Filesystem and get its root
Map<String, String> env = new HashMap<>();
env.put("create", "true");
URI uri = URI.create("jar:" + zipFile.toUri());
FileSystem fileSystem = FileSystems.newFileSystem(uri, env);
Iterable<Path> roots = fileSystem.getRootDirectories();
Path root = roots.iterator().next();
// Simply copy the directory into the root of the zip file system
Files.walkFileTree(sourceDir, new CopyFileVisitor(root));
}
这就是我所说的压缩整个文件夹的优雅方式。但是,在大型文件夹(约3 GB)上使用此方法时,我会收到一个(堆空间)。使用通常的 zip 处理库时,不会引发此错误。因此,似乎处理副本的方式非常低效:太多要写入的文件保存在内存中,因此会发生。OutOfMemoryError
ZipFileSystem
OutOfMemoryError
为什么会这样?使用通常被认为是低效的(就内存消耗而言)还是我在这里做错了什么?ZipFileSystem