如何使用 java - 首选 java8 多线程解压巨大的文件夹?

2023-12-24

参考:http://www.pixeldonor.com/2013/oct/12/concurrent-zip-compression-java-nio/ http://www.pixeldonor.com/2013/oct/12/concurrent-zip-compression-java-nio/

我正在尝试解压缩 5GB 的压缩文件,平均需要大约 30 分钟,这对于我们的应用程序来说是很多时间,我正在努力减少时间。

我尝试了很多组合,更改了缓冲区大小(默认情况下我的写入块是 4096 字节),更改了 NIO 方法、库,所有结果都非常相同。

仍然没有尝试的一件事是将压缩文件按块分割,因此按多线程块读取它。

片段代码是:

  private static ExecutorService e = Executors.newFixedThreadPool(20);
  public static void main(String argv[]) {
        try {
            String selectedZipFile = "/Users/xx/Documents/test123/large.zip";
            String selectedDirectory = "/Users/xx/Documents/test2";
            long st = System.currentTimeMillis();

            unzip(selectedDirectory, selectedZipFile);

            System.out.println(System.currentTimeMillis() - st);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


public static void unzip(String targetDir, String zipFilename) {
    ZipInputStream archive;
            try {
                List<ZipEntry> list = new ArrayList<>();
                archive = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFilename)));
                ZipEntry entry;
                while ((entry = archive.getNextEntry()) != null) {
                    list.add(entry);
                }

                for (List<ZipEntry> partition : Lists.partition(list, 1000)) {
                    e.submit(new Multi(targetDir, partition, archive));
                }
            } catch (Exception e){
                e.printStackTrace();
            }
}

可运行的是:

  static class Multi implements Runnable {

    private List<ZipEntry> partition;
    private ZipInputStream zipInputStream;
    private String targetDir;

    public Multi(String targetDir, List<ZipEntry> partition, ZipInputStream zipInputStream) {
        this.partition = partition;
        this.zipInputStream = zipInputStream;
        this.targetDir = targetDir;
    }

    @Override
    public void run() {
        for (ZipEntry entry : partition) {
            File entryDestination = new File(targetDir, entry.getName());
            if (entry.isDirectory()) {
                entryDestination.mkdirs();
            } else {
                entryDestination.getParentFile().mkdirs();

                BufferedOutputStream output = null;
                try {
                    int n;
                    byte buf[] = new byte[BUFSIZE];
                    output = new BufferedOutputStream(new FileOutputStream(entryDestination), BUFSIZE);
                    while ((n = zipInputStream.read(buf, 0, BUFSIZE)) != -1) {
                        output.write(buf, 0, n);
                    }
                    output.flush();


                } catch (FileNotFoundException e1) {
                    e1.printStackTrace();
                } catch (IOException e1) {
                    e1.printStackTrace();
                } finally {

                    try {
                        output.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }

                }
            }
        }
    }
}

但出于某种原因,它只存储没有文件内容的目录......

我的问题是:关于上述“压缩”文章的方式,在大型 zip 文件上使用多线程制作块的正确方法是什么?


A ZipInputStream https://docs.oracle.com/javase/8/docs/api/java/util/zip/ZipInputStream.html是单个数据流,无法拆分。

如果想要多线程解压,需要使用ZipFile https://docs.oracle.com/javase/8/docs/api/java/util/zip/ZipFile.html。使用 Java 8,您甚至可以免费获得多线程。

public static void unzip(String targetDir, String zipFilename) {
    Path targetDirPath = Paths.get(targetDir);
    try (ZipFile zipFile = new ZipFile(zipFilename)) {
        zipFile.stream()
               .parallel() // enable multi-threading
               .forEach(e -> unzipEntry(zipFile, e, targetDirPath));
    } catch (IOException e) {
        throw new RuntimeException("Error opening zip file '" + zipFilename + "': " + e, e);
    }
}

private static void unzipEntry(ZipFile zipFile, ZipEntry entry, Path targetDir) {
    try {
        Path targetPath = targetDir.resolve(Paths.get(entry.getName()));
        if (Files.isDirectory(targetPath)) {
            Files.createDirectories(targetPath);
        } else {
            Files.createDirectories(targetPath.getParent());
            try (InputStream in = zipFile.getInputStream(entry)) {
                Files.copy(in, targetPath, StandardCopyOption.REPLACE_EXISTING);
            }
        }
    } catch (IOException e) {
        throw new RuntimeException("Error processing zip entry '" + entry.getName() + "': " + e, e);
    }
}

您可能还想查看这个答案 https://stackoverflow.com/a/37413531/5221149,它使用FileSystem https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystem.html访问 zip 文件内容,获得真正的 Java 8 体验。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 java - 首选 java8 多线程解压巨大的文件夹? 的相关文章

随机推荐

  • 如何在 Flask 路由启动之前运行函数?

    我需要在 Flask 路由开始工作之前执行调用功能 我应该在哪里放置函数以使其在服务启动时调用 我做了 app Flask name def checkIfDBExists it is my function if not DBFullPa
  • 从另一个模块覆盖模块方法

    我想从另一个模块 B 重写模块 A 的方法 该方法将对 A 进行猴子补丁 http codepad org LPMCuszt http codepad org LPMCuszt module A def foo puts A end end
  • Rails update_attributes 不保存?

    有没有替代方案update attributes那不保存记录吗 所以我可以做类似的事情 car Car new make gt GMC other processing car update attributes model gt Sier
  • ReadOnly 和 Enabled 之间的主要区别是什么?

    In Windows 窗体 http en wikipedia org wiki Windows Forms控件有两个属性 ReadOnly and Enabled 这两个属性有什么区别 我觉得他们的行为方式是一样的 正如以下论坛帖子中所说
  • SQL Server 2005 根据另一个表字段值的聚合计算列结果

    抱歉问题标题很长 我想我在这件事上是个失败者 但机会很小 是否可以将一个表中的计算字段的计算作为应用于另一个表中的字段的聚合函数的结果 i e 你有一张名为 mug 的桌子 这个桌子有一个名为 color 的孩子 这让我在英国头疼 但供应商
  • 如何在Flutter中实现应用内购买订阅?

    我想在我的 Flutter 应用程序中为 iOS 和 Android 设备提供自动更新订阅 用户可以订阅 1 个月 目前还没有官方维护的应用内购买插件 但是 Flutter 中有很多关于应用内购买的插件 哪一个是最好的 如何实施 这些安全吗
  • 即使禁用 cookie,document.cookie 在 IE11 上仍然可以访问

    使用 IE11 我可以显示所有 cookie 的内容 写出 cookie 找到它并使用 JavaScript 删除它 即使我将隐私设置为 阻止所有 Cookie 实际上 无论我将 IE 模拟设置为哪个版本 document cookie 仍
  • Javascript 中的 For 循环 (document.getElementById)

    我有一点 JavaScript 问题 而不是使用这个 document getElementById hoverinv1 style display document getElementById hoverinv2 style displ
  • Android 上的持久 HttpURLConnections

    我在尝试让 Android 应用程序 好吧 服务 它的情况下它有任何区别 使用持久 HTTP 1 1 连接时遇到问题 以下循环 简化的测试用例 通过桌面 JRE 上的单个 TCP 会话进行工作 但在 Android 设备上会导致整个套接字创
  • 在 React 样式属性中使用 props

    我使用的是带有 ES6 语法的 JSX 这有效 render return div div 这行不通 为什么不行 编辑 它确实有效 render return div div Edit 它可以工作 但样式值必须是有效值 否则它将返回错误 我
  • --line-regexp 选项带有空数据

    考虑这个命令 printf alpha nbravo ncharlie n grep line regexp quiet bravo grep 看到由换行符分隔的 3 行 并与 bravo 行匹配 现在考虑 这个命令 printf alph
  • C 风格字符串、指针、数组

    我无法理解 C 风格字符串是什么 新年快乐 我知道的 指针保存着内存地址 取消引用指针将为您提供该内存位置的数据 int x 50 int ptr x pointer to an integer holds memory address o
  • 以函数式方式遍历树

    我已经在 Scala 中实现了一个基本的可变树 我想以函数方式遍历它以搜索元素 但我不知道如何实现它 如果可能的话 我还希望算法是尾递归的 树是一个具有值和叶子列表的结构 叶子也是树 任何帮助 将不胜感激 这是我的代码 重点关注 getOp
  • 如何使用 Google Compute Engine 安全地配置 App Engine 套接字

    我想在 Google Compute Engine 上放置一个 Redis 服务器 并通过 AppEngine 的套接字支持与其通信 唯一的问题是 似乎没有特定的防火墙规则表明 此 AppEngine 应用程序可以访问此主机 端口 而不能访
  • django URLValidator 产生虚假错误

    我正在使用 DjangoURLValidator形式如下 def clean url self validate URLValidator verify exists True url self cleaned data get url t
  • 使用logging::init_from_stream 增强日志格式单个属性

    当我在代码中设置格式参数时 为了格式化日期时间输出 我可以使用类似的东西 logging formatter simpleFormat expr format 1 2 expr format date time
  • Recyclerview Adapter 和 Glide - 每 4-5 行相同的图像

    我有这个问题 只是为了测试目的我添加ParseFile到其中之一ParseObject从收到的列表中 它不是仅在该行中显示 而是每 4 5 行显示一次 有时更多 有时更少 我怀疑回收观点与此有关 奇怪的是 其他数据 从本示例中删除 可以正常
  • 让 Visual Studio 使用不同的次要版本工具集?

    Under C Program Files x86 Microsoft Visual Studio 2019 Professional VC Tools MSVC 我有不同的目录 例如 14 16 xxxxx 14 24 xxxxx 14
  • 类型“Promise”不可分配给类型“string[]”

    出现以下错误 类型 Promise 不可分配给类型 string 类型 Promise 中缺少属性 includes 当我将 Promise 强制转换为 string 时 我的代码如下 组件 app dashboard ts import
  • 如何使用 java - 首选 java8 多线程解压巨大的文件夹?

    参考 http www pixeldonor com 2013 oct 12 concurrent zip compression java nio http www pixeldonor com 2013 oct 12 concurren