ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java – 使用ZipFileSystem压缩一个巨大的文件夹导致OutOfMemoryError

2019-10-01 02:01:50  阅读:202  来源: 互联网

标签:java zip nio


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通常被认为是低效的(在内存消耗方面)或我在这里做错了什么?

解决方法:

我查看了ZipFileSystem.java,我相信我找到了内存消耗的来源.默认情况下,实现使用ByteArrayOutputStream作为压缩文件的缓冲区,这意味着它受分配给JVM的内存量的限制.

我们可以使用一个(未记录的)环境变量来使实现使用临时文件(“useTempFile”).它的工作原理如下:

Map<String, Object> env = new HashMap<>();
env.put("create", "true");
env.put("useTempFile", Boolean.TRUE);

更多细节:http://www.docjar.com/html/api/com/sun/nio/zipfs/ZipFileSystem.java.html,有趣的线条是96,1358和1362.

标签:java,zip,nio
来源: https://codeday.me/bug/20191001/1837450.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有