Java 多线程写zip文件遇到的错误 write beyond end of stream!
最近在写一个大量小文件直接压缩到一个zip的需求,由于zip中的entry每一个都是独立的,不需要追加写入,也就是一个entry文件,写一个内容,
因此直接使用了多线程来处理,结果就翻车了,代码给出了如下的错误:write beyond end of stream!
下面直接还原当时的代码场景:
1 public class MultiThreadWriteZipFile {
2
3 private static ExecutorService executorService = Executors.newFixedThreadPool(50);
4
5 private static CountDownLatch countDownLatch = new CountDownLatch(50);
6
7
8 @Test
9 public void multiThreadWriteZip() throws IOException, InterruptedException {
10 File file = new File("D:\\Gis开发\\数据\\影像数据\\china_tms\\2\\6\\2.jpeg");
11 //创建一个zip
12 ZipOutputStream zipOutputStream =
13 new ZipOutputStream(new FileOutputStream(new File("E:\\java\\test\\test.zip")));
14
15 for (int i = 0; i < 50; i++){
16 String entryName = i + File.separator + i + File.separator + i + ".jpeg";
17 executorService.submit(() -> {
18 try {
19 writeSource2ZipFile(new FileInputStream(file),entryName,zipOutputStream);
20 countDownLatch.countDown();
21 } catch (IOException e) {
22 e.getLocalizedMessage();
23 }
24 });
25 }
26 //阻塞主线程
27 countDownLatch.await();
28 //关闭流
29 zipOutputStream.close();
30 }
31
32
33 public void writeSource2ZipFile(InputStream inputStream,
34 String zipEntryName,
35 ZipOutputStream zipOutputStream) throws IOException {
36 //新建entry
37 zipOutputStream.putNextEntry(new ZipEntry(zipEntryName));
38 byte[] buf = new byte[1024];
39 int position;
40 //entry中写数据
41 while((position = inputStream.read(buf)) != -1){
42 zipOutputStream.write(buf);
43 }
44 zipOutputStream.closeEntry();
45 zipOutputStream.flush();
46 }
47 }
直接运行上面的代码就会报错:write beyond end of stream
将 private static ExecutorService executorService = Executors.newFixedThreadPool(50);
修改为
private static ExecutorSercvice executorService = Executors.newSingleThreadExecutor();
此时代码运行正常!
至于原因嘛,我们跟踪下代码也就明白其中的原因了,我们先来看报错的代码出处:
在java.util包下的DeflaterOutputStream的201行(jdk1.8,其它版本可能会有差异),我们来看代码
public void write(byte[] b, int off, int len) throws IOException {
if (def.finished()) {
throw new IOException("write beyond end of stream");
}
if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
throw new IndexOutOzfBoundsException();
} else if (len == 0) {
return;
}
if (!def.finished()) {
def.setInput(b, off, len);
while (!def.needsInput()) {
deflate();
}
}
}
关键的原因就是def.finished()对应的状态信息,而这个状态是在Deflater这个类中定义的,这个类也是Java基于ZLIB压缩库实现的,一个压缩工具类。
而下面的这段代码就是改变这个状态的,
public void finish() {
synchronized (zsRef) {
finish = true;
}
}
而这个代码的调用之处,最源头就是我们上面的zipOutputStream.putNextEntry(new ZipEntry(zipEntryName)); 这行代码,
其实先思路,就是每次新增一个entry的时候,都需要将上一次的entry关闭掉,此时也就触发了这个条件,而这个状态并不是线程私有的,我们通过下面的代码就可以知道
public
class Deflater { private final ZStreamRef zsRef;
private byte[] buf = new byte[0];
private int off, len;
private int level, strategy;
private boolean setParams;
private boolean finish, finished;
private long bytesRead;
private long bytesWritten;
因此在多线程下,这个状态肯定是线程不安全的!
好了本次关于多线程下写zip报错的问题,就介绍到这里!
Java 多线程写zip文件遇到的错误 write beyond end of stream!的更多相关文章
- JAVA多线程下载网络文件
JAVA多线程下载网络文件,开启多个线程,同时下载网络文件. 源码如下:(点击下载 MultiThreadDownload.java) import java.io.InputStream; im ...
- java多线程批量读取文件(七)
新公司入职一个多月了,至今没有事情可以做,十来个新同事都一样抓狂,所以大家都自己学习一些新东西,我最近在看zookeeper,感觉蛮不错的,和微服务的zuul以及eureka功能类似,只是代码复杂了一 ...
- Android中用Java代码实现zip文件解压缩
如果需要下载的文件有很多是中文名的,解压时有中文名的文件出现乱码,试了很多方法不能解决问题.据说有一个Java插件包,用这个插件包可以解决中文名乱码的问题,但不知解压的文件是否要用它提供的类压缩后的文 ...
- Java多线程断点下载文件
Java实现断点续传+多线程下载 如下代码所示,每一步都有注解 思路: 通过URL连接到服务器上要下载的文件,得到文件的大小: 算出每条线程下载的开始位置和结束位置,例如,有两条线程下载100Byte ...
- Java—解压zip文件
import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import ja ...
- JAVA解压ZIP文件
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.Inp ...
- Java多线程读取大文件
前言 今天是五一假期第一天,按理应该是快乐玩耍的日子,但是作为一个北漂到京师的开发人员,实在难想出去那玩耍.好玩的地方比较远,近处又感觉没意思.于是乎,闲着写篇文章,总结下昨天写的程序吧. 昨天下午朋 ...
- java多线程批量读取文件( 八)--读写分离
package com.net.thread.future; import java.io.BufferedReader; import java.io.BufferedWriter; import ...
- java IO流 Zip文件操作
一.简介 压缩流操作主要的三个类 ZipOutputStream.ZipFile.ZipInputStream ,经常可以看到各种压缩文件:zip.jar.GZ格式的压缩文件 二.ZipEntry ...
随机推荐
- numa 自动balance 的bug分析
关于migrate_swap() 和 active_balance()之间的hardlock 背景:这个是在3.10.0-957.el7.x86_64 遇到的一例crash 下面列一下我们是怎么排查并 ...
- i40e网卡驱动遇到的一个问题
最近在排查一个crash文件的时候,遇到一个堆栈,即软中断收包的时候,skb的关联的dev是null,导致oops, 然后去crash分析的时候,发现skb的dev去不是null. 从oops到cra ...
- 一次客户需求引发的K8S网络探究
前言 在本次案例中,我们的中台技术工程师遇到了来自客户提出的打破k8s产品功能限制的特殊需求,面对这个极具挑战的任务,攻城狮最终是否克服了重重困难,帮助客户完美实现了需求?且看本期K8S技术案例分享! ...
- 【AGC】如何快速部署Serverless Url缩短模板
使用场景 Serverless短URL生成模板实现您将在云数据库服务中URL缩短的诉求.使用此模板后,仅需在云数据库服务侧配置长URL值.Serverless短URL生成模板会在后台与Bitly AP ...
- 因势而变,因时而动,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang泛型(generic)的使用EP15
事实上,泛型才是Go lang1.18最具特色的所在,但为什么我们一定要拖到后面才去探讨泛型?类比的话,我们可以想象一下给小学一年级的学生讲王勃的千古名篇<滕王阁序>,小学生有多大的概率可 ...
- spark 读取Geomesa(Hbase)数据
package com.grady.geomesa import org.apache.hadoop.conf.Configuration import org.apache.spark.SparkC ...
- shell脚本自动化部署Zabbix4.2(修改脚本替换版本)
#!/bin/bash # 检查操作系统版本,该脚本只能运行在 Centos 7.x 系统上 cat /etc/redhat-release |grep -i centos |grep '7.[[:d ...
- 跟羽夏学 Ghidra ——窗口
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...
- Docker安装MySQL并使用Navicat连接
MySQL简单介绍: MySQL 是一个开放源码的关系数据库管理系统,开发者为瑞典 MySQL AB 公司.目前 MySQL 被广泛地应用在 Internet 上的大中小型网站中.由于其体积小.速度快 ...
- 在 AlertManager 报警通知中展示监控图表
原文档地址:https://mp.weixin.qq.com/s/Wcp7ltEbnHpUlbaF9JDgZg 去绘制渲染报警图表,然后上传到对象存储中保存起来,在钉钉中就可以直接展示了,Promot ...