多线程压缩ZIP文件

工作过程中,可能会遇到有需要生成压缩包的需求,而生成压缩包,一般速度不快,比较影响效率,所以一般会考虑使用多线程进行压缩。本文就多线程压缩方式进行以下介绍
多线程压缩一般分为两种方式

  • 多线程读源文件,单线程写ZIP文件
  • 使用common-compress工具包进行多线程压缩

1.多线程读源文件,单线程写ZIP文件

该方法是使用多线程先将需要压缩的源文件读取出来,然后再单线程写入ZIP中
下面先看代码

@Test
void test3() throws IOException, InterruptedException {// 初始化线程池ExecutorService executorService = Executors.newFixedThreadPool(10);long start = System.currentTimeMillis();// 初始化ZIP输出流ZipOutputStream zops = new ZipOutputStream(Files.newOutputStream(Paths.get("multiFile.zip")));File file = new File("C:\\Users\\Administrator\\Desktop\\CodeFormer");List<TestZipDownloadBean> list = new ArrayList<>();// 递归读取源文件夹下所有文件,并记录其路径信息getFileList(file, list);// 初始化计数器,用于线程等待CountDownLatch countDownLatch = new CountDownLatch(list.size());// 初始化锁对象Lock lock = new ReentrantLock();for (TestZipDownloadBean bean : list) {executorService.execute(() -> {try(InputStream ips = Files.newInputStream(Paths.get(bean.getPath()));) {// 根据源文件绝对路径信息,生成压缩包内的相对路径信息,// 此处需要根据自己的压缩文件信息进行自定义设置String relativePath = bean.getPath().substring(bean.getPath().lastIndexOf("CodeFormer\\") + 11);String path = relativePath.contains("\\") ? relativePath.substring(0, relativePath.lastIndexOf("\\")) : null;String fileName = relativePath.contains("\\") ? relativePath.substring(relativePath.lastIndexOf("\\") + 1) : relativePath;// 初始化ZipEntryZipEntry zipEntry = new ZipEntry(path == null ? fileName : (path + "/" + fileName));// 加锁,这边加锁是因为,ZIP输出流如果想添加新的ZipEntry的话,// 就必须关闭前一个ZipEntry,所以这边只能加锁等待。// ZipEntry可以理解为就是ZIP中的一个一个文件lock.lock();zops.putNextEntry(zipEntry);// 这边每次读取的文件大小,尽量以单个文件大小为准,// 这样每次就可以把一个文件完整读取出来,速度能快一点点// 如果没有文件大小信息的话,就每次读取10Kb,这个大小可以根据需求自定义byte[] bytes = new byte[bean.getFileLength() == null ? (1024*10) : bean.getFileLength().intValue()];int len;// 通过二进制流写文件while ((len = ips.read(bytes)) > 0) {zops.write(bytes, 0, len);}// 关闭ZipEntryzops.closeEntry();// 释放锁lock.unlock();// 刷新缓存zops.flush();} catch (Exception e) {System.out.println(Thread.currentThread().getName() + "读取文件异常,文件路径:" + bean.getPath());}// 计数器减一,这边一定不能遗漏,否则程序会一直等待,不会停止countDownLatch.countDown();});}// 阻塞,等待全部线程完成文件压缩countDownLatch.await();// 关闭ZIP输出流zops.close();long end = System.currentTimeMillis();System.out.println("耗时:" + (end - start));
}

该代码逻辑就是,先递归获取文件列表,然后再使用多线程进行文件读取,文件读取完毕后,再使用加锁的方式,对多线程文件写进行串行化设置。这边文件写ZIP的时候是无法进行多线程写入的,因为写ZIP的时候是写入一个一个的ZipEntry对象的,而ZipEntry对象是要通过putNextEntry方法设置的,在每次设置新的ZipEntry之前,必须先关闭前一个ZipEntry才行,如果是多线程并发写的话,就无法保证这个顺序,所以这边需要加锁进行串行化操作。
如果需要在ZIP文件生成子文件夹的话,也是很方便的,只需要写上路径名加上文件名,即可自动创建子文件夹了,例如写文件时,文件名为"a/a.txt",那么ZIP生成之后,解压就会出现一个a文件夹,里面有一个a.txt文件。

递归获取文件列表代码

/*** 递归获取文件及其路径信息* * @param file 文件对象* @param fileList 文件信息集合*/
private void getFileList(File file, List<TestZipDownloadBean> fileList){if (file == null) {return;}// 如果是文件夹,就继续递归if (file.isDirectory()) {for (File tempFile : Objects.requireNonNull(file.listFiles())) {getFileList(tempFile, fileList);}}// 如果是文件,就解析一下,放到文件集合中if (file.isFile()) {TestZipDownloadBean bean = new TestZipDownloadBean(null, file.getAbsolutePath());bean.setFileLength(file.length());fileList.add(bean);}
}

2.使用common-compress工具包进行多线程压缩

这个方式需要使用到第三方依赖,可以使用maven进行依赖导入

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-compress</artifactId><version>1.21</version>
</dependency>

依赖导入之后,就可以进行代码编写了,以下是使用工具包的代码示例

@Test
void test4() throws IOException, ExecutionException, InterruptedException {// 初始化线程池ExecutorService executorService = Executors.newFixedThreadPool(10);long start = System.currentTimeMillis();// 初始化并行Zip创建器对象ParallelScatterZipCreator parallelScatterZipCreator = new ParallelScatterZipCreator(executorService);// 初始化Zip文件输出流OutputStream outputStream = Files.newOutputStream(Paths.get("multiFile.zip"));// 初始化Zip输出流ZipArchiveOutputStream zaops = new ZipArchiveOutputStream(outputStream);// 设置流文件编码zaops.setEncoding("UTF-8");File file = new File("C:\\Users\\Administrator\\Desktop\\CodeFormer");List<TestZipDownloadBean> list = new ArrayList<>();// 递归获取文件列表getFileList(file, list);for (TestZipDownloadBean bean : list) {// 生成源文件输入流InputStreamSupplier streamSupplier = () -> {try {return Files.newInputStream(Paths.get(bean.getPath()));} catch (IOException e) {throw new RuntimeException(e);}};// 根据源文件绝对路径信息,生成压缩包内的相对路径信息,// 此处需要根据自己的压缩文件信息进行自定义设置String relativePath = bean.getPath().substring(bean.getPath().lastIndexOf("CodeFormer\\") + 11);String path = relativePath.contains("\\") ? relativePath.substring(0, relativePath.lastIndexOf("\\")) : null;String fileName = relativePath.contains("\\") ? relativePath.substring(relativePath.lastIndexOf("\\") + 1) : relativePath;// 生成ZipEntry对象ZipArchiveEntry zipArchiveEntry = new ZipArchiveEntry(path == null ? fileName : (path + "/" + fileName));// 设置压缩方法,只有ZipEntry.DEFLATED和ZipEntry.STORED两个取值// ZipEntry.STORED方法压缩后文件体积不会变小,速度很快// ZipEntry.DEFLATED方法压缩后文件体积会变小,但是速度要慢一些zipArchiveEntry.setMethod(ZipEntry.DEFLATED);parallelScatterZipCreator.addArchiveEntry(zipArchiveEntry, streamSupplier);}// 开始压缩文件parallelScatterZipCreator.writeTo(zaops);// 关闭zip输出流zaops.close();// 关闭文件输出流outputStream.close();long end = System.currentTimeMillis();System.out.println("耗时:" + (end - start));
}

以上就是使用commons-compress工具包进行多线程压缩的方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/143203.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker-compose 部署 MySQL 8

目录 前言MySQL 配置文件(my.cnf)docker-compose.yml安装卸载 前言 Windows/Linux 系统通过 docker-compose 部署 MySQL8.0。 MySQL 配置文件(my.cnf) # 服务端参数配置 [mysqld] usermysql # MySQL启动用户 default-storage-engineINNODB # 创建新表时…

HTTP代理与SOCKS5代理,有什么区别?

在数字通信领域&#xff0c;数据安全和匿名性都是非常重要的指标。互联网的不断发展催生了几种协议&#xff0c;每种协议都有独特的优势和挑战。其中&#xff0c;SOCKS5 代理、HTTP代理最为广泛使用&#xff0c;下面给大家一起讨论&#xff0c;HTTP代理与SOCKS5代理&#xff0c…

POE也收费了

一直通过POE在用chatgpt&#xff0c;今天下午发现要收费了…

开发知识点-Vue-Electron

Electron ElectronVue打包.exe桌面程序 ElectronVue打包.exe桌面程序 为了不报错 卸载以前的脚手架 npm uninstall -g vue-cli安装最新版脚手架 cnpm install -g vue/cli创建一个 vue 随便起个名 vue create electron-vue-example (随便起个名字electron-vue-example)进入 创建…

ai语音电销机器人电销行业要怎么降低封号率?

工信部对电话营销电话的管控越来越严格&#xff0c;企业电销行业的发展受到了很多限制&#xff0c;因为电话销售人员在进行销售工作的时候&#xff0c;经常会因为各种原因触发封号机制&#xff0c;导致手机卡号被封&#xff0c;那企业电销行业要怎么降低封号率&#xff1f; 很多…

vue+iView实现下载zip文件导出多个excel表格

1&#xff0c;需求&#xff1a;在vue项目中&#xff0c;实现分月份导出多个Excel表格。 点击导出&#xff0c;下载zip文件&#xff0c;解压出多张表数据。 2&#xff0c;关键代码&#xff1a; <Button class"export button-style button-space" click"ex…

ssm823基于ssm的心理预约咨询管理系统的设计与实现+vue

ssm823基于ssm的心理预约咨询管理系统的设计与实现vue 交流学习&#xff1a; 更多项目&#xff1a; 全网最全的Java成品项目列表 https://docs.qq.com/doc/DUXdsVlhIdVlsemdX 演示 项目功能演示&#xff1a; ————————————————

【QT HTTP】使用QtNetwork模块制作基于HTTP请求的C/S架构

目录 0 引言1 HTTP基本知识1.1 请求类型1.2 HTTP请求报文格式1.3 HTTP响应报文格式1.4 拓展&#xff1a;GET vs POST 请求方法GET请求请求报文&#xff1a;响应报文 POST请求请求报文响应报文 其他注意事项示例&#xff1a;GET请求示例POST请求示例 2 实战2.1 QtNetwork模块介绍…

电脑指示灯闪烁,但是无法开机的解决方案

【便携机开机故障】电脑指示灯闪烁&#xff0c;但是无法开机的解决方案 问题描述 设备型号&#xff1a;联想 ThinkPad T14s 故障详情&#xff1a;电脑使用后未关机锁屏合盖后&#xff0c;再次使用时开关机指示灯一直闪烁&#xff0c;但是无法正常开机。 其他尝试方法&#xf…

Kafka 的应用场景

Kafka 是一个开源的分布式流式平台&#xff0c;它可以处理大量的实时数据&#xff0c;并提供高吞吐量&#xff0c;低延迟&#xff0c;高可靠性和高可扩展性。 Kafka 最初是为分布式系统中海量日志处理而设计的。它可以通过持久化功能将消息保存到磁盘&#xff0c;并让消费者按…

Express基本接口开发-入门学习与后续进阶

前提推荐 任何一个新的知识都是从文档看起&#xff0c;因此express官方文档示例有必要去学习一遍。 推荐看&#xff1a; 推荐入门指南-路由指南-中间件 看完这几个内容之后心里大概知道express有些什么东西了&#xff0c;然后现在就可以去练习了 注意&#xff1a;更多示例-代…

安全区域边界(设备和技术注解)

网络安全等级保护相关标准参考《GB/T 22239-2019 网络安全等级保护基本要求》和《GB/T 28448-2019 网络安全等级保护测评要求》 密码应用安全性相关标准参考《GB/T 39786-2021 信息系统密码应用基本要求》和《GM/T 0115-2021 信息系统密码应用测评要求》 1边界防护 1.1应保证跨…

03-CSS基础选择器

3.1 CSS基础认知&#x1f34e; 3.1.1 &#x1f441;️‍&#x1f5e8;️CSS概念 CSS&#xff1a;层叠样式表&#xff08;Cascading style sheets)&#xff0c;为网页标签增加样式表现的 语法格式&#xff1a; 选择器{<!-- 属性设置 -->属性名:属性值; <!--每一个…

阿里云C++二面面经

1.智能指针 1、shared_ptr 原理:shared_ptr是基于引用计数的智能指针,用于管理动态分配的对象。无论 std::shared_ptr 存储在堆区还是栈区,它所指向的内存块始终存储在堆区。这是因为 std::shared_ptr 是用于管理动态分配的内存的智能指针,它需要存储在堆区,以便进行引用…

直流电动机四象限运行控制变流器设计

摘 要 节能和效率是工业经济发展的主题&#xff0c;电机在各行各业都是主要的动力来源&#xff0c; 直流电机以其控制简单&#xff0c;效率高&#xff0c;功率密度大等优势脱颖而出。基于直流电动机四象限运行控制变流器应用广泛&#xff0c;比如电子设备、电机控制、工业等行…

Spring Cloud Netflix微服务组件-Eureka

CAP理论 分区容忍是能容忍一个或一部分节点挂掉后&#xff0c;整体系统也能正常工作&#xff08;就是别的节点还是活着的&#xff09;&#xff0c;所以分布式系统中P是必须要有的。比如数据库主从架构&#xff0c;主从两个节点之间需要数据同步&#xff0c;主挂了&#xff0c;…

Mysql中的索引与事务和B树的知识补充

索引与事务和B树的知识补充 一.索引1.概念2.作用3.使用场景4.使用 二.事务1.为什么使用事务2.事务的概念3.使用3.1脏读问题3.2不可重复读3.3 幻读问题3.4解决3.5 使用代码 三.B树的知识补充1.B树2.B树 一.索引 1.概念 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记…

Git常用配置

git log 美化输出 全局配置参数 git config --global alias.lm "log --no-merges --color --dateformat:%Y-%m-%d %H:%M:%S --authorghost --prettyformat:%Cred%h%Creset - %Cgreen(%cd)%C(yellow)%d%Cblue %s %C(bold blue)<%an>%Creset --abbrev-commit"…

程序员一般从什么平台兼职接私活?国内外主流9大平台汇总!

我想对于有一定工作经验的工程师来说&#xff0c;肯定听说过或者切身经历过公司裁员、公司倒闭、甚至清退年龄稍大的工程师等一系列负面情况。 其实我们作为员工来说&#xff0c;面对这些打击&#xff0c;我们能争取到的权益是比较少的&#xff0c;即使争取到了一些权益或补偿…

如何实现MQTT协议数据传输?

如何实现MQTT协议数据传输&#xff1f; 随着物联网技术的不断发展&#xff0c;越来越多的设备和应用需要实现互联互通。而MQTT作为一种轻量级的发布/订阅消息传输协议&#xff0c;在物联网领域应用广泛&#xff0c;成为了许多设备之间数据交互的首选。蓝蜂物联网推出的MQTT网关…