JAVA实现zip压缩需要注意的问题
近来对院社二维码平台进行2.0升级改造。于昨日踩到一个巨坑。特此记录。。。
需求源于院社编辑在批量下载二维码的时候,系统后台需要对所要下载的二维码进行重命名和zip打包压缩。
系统测试的时候发现:首次请求批量下载时,也即压缩文件还未生成时,后台可以正常压缩文件并提供下载。但是第二次请求批量下载时,网页一直无反应。。。
尝试了几次后仍旧没反应。只好查看tomcat日志,惊奇的发现日志只写了一半,后半部分丢失(第一次遇到这种情况)==|||
不过老天爷保佑,写入的一部分显示:No space left device.
我擦!硬盘满了?昨天还有68%的余量。今天就没了?
迅速df du命令走起。du显示并没有占满。但是df显示已经100%。这是搞毛。。
google一下,发现du df显示结果不一样的原因可能是有文件句柄没有释放,文件仍旧被进程占用。df统计的是硬盘实际占用,而du并不包括已经标记删除却仍旧被进程占用,实际上并未物理删除的文件。(文件物理删除和标识为deleted不是一个概念)
接着调用lsof | grep deleted查看文件占用情况。。果然那几个zip文件size已经突破天际了。。
看来是java对zip文件打包时出错了。陷入了死循环???
由于zip打包源码是同事提供的,并没有深入了解。不得不扒开package,查看到底是个啥子逻辑。
经过一番折腾。终于发现问题。
举个例子:
a文件下有1.jpg 2.jpg两个文件
在第一次请求批量下载时,生成了b.zip文件。
如此a文件夹下就有了1.jpg 2.jpg b.zip文件了
根据源码逻辑,首先会对a文件夹进行遍历搜索,然后将每个文件逐个加入zip文件中。
那么,第二次请求时,从表面上看,可能会粗略的以为b.zip会被覆盖掉,替换成新b.zip,里面包括1.jpg 2.jpg 和旧的b.zip。
大错特错!
文件在进行写操作时,始终是对同一个b.zip在操作!
分解一下过程。首先在遍历a文件夹得到三个文件名的列表:1 2 b
创建新b时,旧b文件会被删除,但是b这个文件名仍旧保留在上面的文件列表中。
接下来,添加1到新b,添加2到新b。
在添加旧B的时候,实则在对新B操作!!如果从文件读写指针的角度来看,如下图所示
read write
1 2 (12)
可以看到,由于是在对同一个文件操作,read指针永远不可能赶上write,也即EOF,那么这个写就永无止境。
所以解决bug的方法是:把要打包的文件和目标zip文件放在两个不同的文件夹下面。这样就不会始终对同一个zip文件又读又写了。
此外,我还在windows平台上进行了测试。发现一个很诡异的现象。在windows上文件能够正常下载,且不会出现磁盘容量爆棚的情况。但是:
1)新打包的b.zip里面还有一个b.zip。
2)外层的b.zip可以正常解压,里层的b.zip也可以解压和查看。但是里层的b.zip解压时会报文件末端错误。
3)里层的b.zip还有一个b.zip,暂且叫做里里层b.zip。这个里里层b.zip就完全打不开了。
4)用资源管理器查看tomcat所掌握的资源句柄,仍旧包括这个最外层的b.zip。也就是即便client完成了下载,服务端也没有释放这个资源。
可以说,windows遇到了和linux平台一样的问题。但是可能因为windows操作系统的文件系统具体细节的处理方式不同,导致出现了最后这样一个相对诡异的结果。
JAVA实现zip压缩需要注意的问题的更多相关文章
- Java 的zip压缩和解压缩
Java 的zip压缩和解压缩 好久没有来这写东西了,今天中秋节,有个东西想拿出来分享,一来是工作中遇到的问题,一来是和csdn问候一下,下面就分享一个Java中的zip压缩技术,代码实现比较简单,代 ...
- 用java实现zip压缩
本来是写到spaces live上的,可是代码的显示效果确实不怎么好看.在javaeye上试了试代码显示的顺眼多了. 今天写了个用java压缩的功能,可以实现对文件和目录的压缩. 由于java.uti ...
- Java实现zip压缩多个文件下载
为了更好的演示,首先创建一个文件实体FileBean,包含了文件路径和文件名称: package com.javaweb.entity; import java.io.Serializable; /* ...
- Java操作zip压缩和解压缩文件工具类
需要用到ant.jar(这里使用的是ant-1.6.5.jar) import java.io.File; import java.io.FileInputStream; import java.io ...
- java.util.zip压缩打包文件总结二: ZIP解压技术
一.简述 解压技术和压缩技术正好相反,解压技术要用到的类:由ZipInputStream通过read方法对数据解压,同时需要通过CheckedInputStream设置冗余校验码,如: Checked ...
- java.util.zip压缩打包文件总结一:压缩文件及文件下面的文件夹
一.简述 zip用于压缩和解压文件.使用到的类有:ZipEntry ZipOutputStream 二.具体实现代码 package com.joyplus.test; import java.io ...
- java基础---->Zip压缩的使用(转)
java中提供了对压缩格式的数据流的读写.它们封装到现成的IO 类中,以提供压缩功能.下面我们开始java中压缩文件的使用. 目录导航: 关于压缩的简要说明 GZIP压缩文件的使用 ZIP压缩文件的使 ...
- java基础---->Zip压缩的使用
java中提供了对压缩格式的数据流的读写.它们封装到现成的IO 类中,以提供压缩功能.下面我们开始java中压缩文件的使用. 目录导航: 关于压缩的简要说明 GZIP压缩文件的使用 ZIP压缩文件的使 ...
- java实现zip压缩和解压工具
引入ant.jar package com.develop.web.util; import java.io.BufferedInputStream; import java.io.File; imp ...
随机推荐
- Hash表及hash算法的分析
Hash表中的一些原理/概念,及根据这些原理/概念: 一. Hash表概念 二. Hash构造函数的方法,及适用范围 三. Hash处理冲突方法,各自特征 四. ...
- ngxin error日志
日志模块ngx_errlog_module对于支持可变参数平台提供的三个接口 #define ngx_log_error(level, log, ...) \ if ((log)->log_le ...
- HDU 5298 Solid Geometry Homework 暴力
Solid Geometry Homework 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5298 Description Yellowstar ...
- hdu 5207 Greatest Greatest Common Divisor 数学
Greatest Greatest Common Divisor Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/ ...
- 去除两端margin的方法
假如有一份视觉稿,其中一部分是实现这样的: 两排横向排列的框,它们中间有边距,两端无边距.每个框大小为100*100,外边距为20,整个区域为460*220. HTML结构: <div> ...
- SilverLight学习笔记--使用WebClient实现通讯(一)(上传和下载字符串数据)
一.什么是WebClient类 1.基本知识 WebClient类是Mircsoft在.NET框架下提供的向 URI 标识的资源发送数据和从 URI 标识的资源接收数据的公共方法.通过这个类 ...
- python核心模块之pickle和cPickle解说
pickle模块使用的数据格式是python专用的,而且不同版本号不向后兼容,同一时候也不能被其它语言说识别.要和其它语言交互,能够使用内置的json包使用pickle模块你能够把Python对象直接 ...
- iTunes Connect App Bundles
App Bundles捆绑销售提交流程: 1. 在iTunes Connect左上「+」选「Create Bundle」到「New App Bundle」挑选已上线应用(最多可捆绑10个应用) 2. ...
- Shuttle ESB(四)——公布订阅模式实例介绍(1)
前面,我已经集中用了三篇文章来讲Shuttle ESB的入门实例与宏观概念. Shuttle ESB一共同拥有两种发送消息的模式:请求/对应模式与Pub/Sub模式. 关于这两种模式的区分.请看以下文 ...
- Java垃圾回收精粹 — Part2
Java垃圾回收精粹分4个部分,本篇是第2部分.在第2部分里介绍了Hotspot中的堆结构.对象分配以及次要回收. Hotspot中的堆结构 理解不同的收集器的工作方式,是探讨Java堆结构如何支持分 ...