java.nio
包以一种优美的方式处理zip文件,将它们视为文件系统。这使我们能够像对待普通文件一样处理zip文件内容。因此,只需使用Files.copy
将所有文件复制到zip文件中,就可以轻松地压缩整个文件夹。由于子文件夹也需要被复制,所以我们需要一个访问者:
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;
}
}
这是一个简单的“递归复制目录”访问器。它用于递归地复制目录。然而,使用ZipFileSystem
,我们也可以将其用于将目录复制到zip文件中,像这样:
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)上使用此方法时,会收到OutOfMemoryError
(堆空间)错误。当使用常规的 zip 处理库时,不会出现此错误。因此,看起来 ZipFileSystem
处理复制的方式非常低效:太多要写入的文件被保存在内存中,导致OutOfMemoryError
错误。
为什么会出现这种情况?使用ZipFileSystem
一般被认为是低效的(在内存消耗方面),还是我在这里做错了什么?
tmppaths
。 - Marcono1234useTempFile
必须是一个带有true
值的布尔类型,而create
必须是一个值为true
的字符串。难以置信这甚至成为了标准。 - Philipp