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 ...
随机推荐
- pathlib路径问题
下面是我的文件框架 app ------ file1---- .py1 file2---- .py2 config.py 我在config文件中设置了变量参数 BASE_DIR = pathlib.P ...
- KingbaseES V8R6兼容Oracle的exp-imp导出导入工具使用
说明: KingbaseES V8R6版本中的兼容Oracle的exp-imp导入导出工具,支持完全模式.用户模式和表模式的导出功能. 本次案例数据库版本: test=# select version ...
- KingbaseES V8R6单实例外部备份故障案例
案例说明: 在KingbaseES V8R6单实例环境,配置外部备份服务器使用sys_backup.sh物理备份时,出现以下"WAL segment xxx was not archived ...
- 使用SSH连接Windows Server
之前发过一篇在Windows Server上启用SSH服务器的文章.最近正好有这个需求,需要使用密钥免密登录服务器,试了一下,发现之前的方法不行了.需要再修正一些文件权限. 需要使用Repair-Au ...
- Python-Django模板
前面将hello world输出给浏览器,将数据与 视图 混合在一起,不符合 MVC思想. 模板就是一个文本,用来分离文档的表现形式和内容. 在templates目录下创建一个html模板 然后需要向 ...
- 【Tool】Idea快捷键
Windows Ctrl + F12: 查找当前类中的方法 Ctrl + N: 查找类 Ctrl + Alt + H: 查看方法调用关系 Ctrl + H: 查看类的继承关系 Alt + F7:查找类 ...
- 在 CentOS 8 上使用 FirewallD 设置防火墙
简介 一个 Linux 防火墙可用于保护您的工作站或服务器免受不需要的流量干扰.您可以设置规则来阻止或允许流量通过.CentOS 8 带有一个动态的.可定制的基于主机的防火墙和一个 D-Bus 接口. ...
- 10.第九篇 kube-scheduler 安装及验证
文章转载自在:https://mp.weixin.qq.com/s?__biz=MzI1MDgwNzQ1MQ==&mid=2247483830&idx=1&sn=787de8d ...
- Prometheus高可用部署
Prometheus的本地存储给Prometheus带来了简单高效的使用体验,可以让Promthues在单节点的情况下满足大部分用户的监控需求.但是本地存储也同时限制了Prometheus的可扩展性, ...
- 跟我学Python图像处理丨傅里叶变换之高通滤波和低通滤波
摘要:本文讲解基于傅里叶变换的高通滤波和低通滤波. 本文分享自华为云社区<[Python图像处理] 二十三.傅里叶变换之高通滤波和低通滤波>,作者:eastmount . 一.高通滤波 傅 ...