Java多线程写zip文档碰到的错误writebeyondendofstream!


Java多线程写zip文档碰到的错误writebeyondendofstream!

近期在写一个大量小文件直接压缩到一个zip的需求,因为zip中的entry每一个都是独立的,不需要增加写入,也就是一个entry文件,写一个内容,
因此直接用了多线程去处理,结果就翻车了,代码给出了如下的错误:writebeyondendofstream!
下面直接还原当时的代码情景:
复制代码
1publicclassMultiThreadWriteZipFile{
2
3privatestaticExecutorServiceexecutorService=Executors.newFixedThreadPool(50);
4
5privatestaticCountDownLatchcountDownLatch=newCountDownLatch(50);
6
7
8@Test
9publicvoidmultiThreadWriteZip()throwsIOException,InterruptedException{
10Filefile=newFile("D://Gis开发//数据//影像数据//china_tms//2//6//2.jpeg");
11//建立一个zip
12ZipOutputStreamzipOutputStream=
13newZipOutputStream(newFileOutputStream(newFile("E://java//test//test.zip")));
14
15for(inti=0;i<50;i++){
16StringentryName=i+File.separator+i+File.separator+i+".jpeg";
17executorService.submit(()->{
18try{
19writeSource2ZipFile(newFileInputStream(file),entryName,zipOutputStream);
20countDownLatch.countDown();
21}catch(IOExceptione){
22e.getLocalizedMessage();
23}
24});
25}
26//堵塞主线程
27countDownLatch.await();
28//关掉流
29zipOutputStream.close();
30}
31
32
33publicvoidwriteSource2ZipFile(InputStreaminputStream,
34StringzipEntryName,
35ZipOutputStreamzipOutputStream)throwsIOException{
36//新建entry
37zipOutputStream.putNextEntry(newZipEntry(zipEntryName));
38byte[]buf=newbyte[1024];
39intposition;
40//entry中写数据
41while((position=inputStream.read(buf))!=-1){
42zipOutputStream.write(buf);
43}
44zipOutputStream.closeEntry();
45zipOutputStream.flush();
46}
47}
复制代码
直接运行上边的代码便会报错:writebeyondendofstream
将privatestaticExecutorServiceexecutorService=Executors.newFixedThreadPool(50);
修改为
privatestaticExecutorSercviceexecutorService=Executors.newSingleThreadExecutor();
这时代码运行正常!
至于原因嘛,我们追踪下代码也就明白其中的原因了,我们先来看报错的代码出处:
在java.util包下的DeflaterOutputStream的201行(jdk1.8,其它版本可能会有差别),我们来看代码
复制代码
publicvoidwrite(byte[]b,intoff,intlen)throwsIOException{
if(def.finished()){
thrownewIOException("writebeyondendofstream");
}
if((off|len|(off+len)|(b.length-(off+len)))<0){
thrownewIndexOutOzfBoundsException();
}elseif(len==0){
return;
}
if(!def.finished()){
def.setInput(b,off,len);
while(!def.needsInput()){
deflate();
}
}
}
复制代码
关键的原因就是def.finished()对应的状态信息,而这个状态是在Deflater这个类中定义的,这个类也是Java基于ZLIB压缩库达到的,一个压缩工具类。
而下面的这段代码便是改变这个状态的,
publicvoidfinish(){
synchronized(zsRef){
finish=true;
}
}
而这个代码的调用之处,最根源是我们上边的zipOutputStream.putNextEntry(newZipEntry(zipEntryName));这行代码,
其实先思路,便是每次新增一个entry的时候,都要将上一次的entry关掉掉,这时也就触发了这个条件,而这个状态并不是进程私有的,我们通过下边的代码就可以知道
复制代码
public
classDeflater{
privatefinalZStreamRefzsRef;
privatebyte[]buf=newbyte[0];
privateintoff,len;
privateintlevel,strategy;
privatebooleansetParams;
privatebooleanfinish,finished;
privatelongbytesRead;
privatelongbytesWritten;

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/292639.html

(0)
上一篇 2022年11月5日
下一篇 2022年11月6日

相关推荐

发表回复

登录后才能评论