Java压缩和解压缩(六)总结二

Java压缩和解压缩
placeholder image
admin 发布于:2023-09-18 08:26:28
阅读:loading

前面一篇总结《Java压缩和解压缩(五)总结一》算是对压缩和解压缩的组件进行了一次介绍,本次将对于使用它们在实际项目中的应用层面的总结,针对于我个人所遇到的实际需求场景,也许这些总结也就只适合我这边,读者仍需站在自己的需求场景进行自身评估。

1. 需求场景

(1)每天需被动解析成百上千个压缩包文件,以解压缩文件为主,文件名称不限制;

(2)解压缩的文件各种各样,可以是用户自己生成的压缩包,也可以是用代码生成的压缩包,比如可以是Windows、Linux、Mac等多平台生成的;

(3)解压缩的文件格式支持多种常见格式,比如zip、7z、rar(rar还区分4和5的版本);

(4)解压缩的文件需要支持密码解压,解密文件时区分加密文件名(打开压缩包文件时无法获取文件的列表,不知道压缩的源文件是什么名字)和普通的密码加密(不知道密码时可以知晓源文件的文件名称)

2. 技术选型

在编码之初,本着多学习钻研的想法全面的学习掌握了几款压缩和解压缩的组件,并且针对于它们各自都做了相关的实践,最终决定按以下几个思路进行编码,具体如下:

(1)zip4j 是功能全面的zip格式压缩和解压缩的开源项目(看了GitHub介绍貌似是个人开发者),使用它专职处理zip格式;

(2)Apache Commons Compress 毕竟也是Apache出品的,质量上无需担忧,专职用于处理7z格式;

(3)7-Zip-jbinding 虽然也支持各个操作系统,但它内部包含了一些动态链接库的实现方式,不作为优先考虑的场景,再加上实际上用户生成的rar格式的文件或许并不多,所以它仅被视为rar格式的实现;

(4)jdk里面的解压缩实现太鸡肋,不支持解压缩密码,所以只能往边上站了;

3. 踩坑记录

前期技术调研时,各种格式的压缩包文件都有普及到,但是不够全面,仍然受不同操作系统平台的限制或压缩包的生成方式,出现了各种各样的问题,整理如下:

(1)zip4j解压缩的密码报错问题?

实际上密码是正确的,但是就是无法解压缩,因为我用一些360压缩工具或7z压缩工具都可以正常解压缩的,但是使用zip4j在代码中就是无法解压,在GitHub的项目问题库也有外国选手提出该问题,跟他一样,我无法提供出不能解压缩成功的文件;

(2)zip4j解压缩的乱码问题?

zip4j在解压缩时支持传递字符编码进行解压缩,换句话说在解压缩文件时,我们并不知道文件是在什么操作系统平台下生成的,我们无法固定的传递解压缩编码,也不能固定写成某种编码类型,所以前期在写成了GBK后,在成百上千个解压缩的场景下自然而然就出现了乱码了,至于乱码的解决也尝试了以下几种方式的实现:

A.使用开源项目获取文件的编码,从而使用编码进行解压缩,似乎这些获取到的仍然是压缩包文件本身的编码,而不是他里面解压缩文件对应的编码,如使用cpdetector组件,经过尝试这种方式并不正确;

B.默认优先使用GBK编码(该编码是Windows平台生成的压缩包,大多数都是这个编码),遍历压缩后的所有文件,得到它们的文件名称,根据文件名称来判断它们是否包含乱码,若包含则再将已解压的全部文件删除,换成UTF-8编码重新进行解压缩;

C.经过尝试,觉得第2种方式尚可吧,但是判断是否为乱码的方式需要特别注意,常规的根本不行,因为有些特殊的文字被转换为了并不常用的中文,实际它们并不是乱码,如:“姞”、“囦”等,所以实际还是不行,难道要根据所有的乱码范围来穷举一个被视为乱码的范围吗,所以还是放弃了这种方式,虽然通过穷举的方式绝大多数的解决了附件乱码的情况,但是还是存在诟病的地方;

(3)使用Apache Commons Compress项目解压一些7z格式的文件时,对于有密码的压缩包时,密码包含字母和数字组合,解压缩报错了,搜索了一下说是密码的复杂度高了,需要下载对应JDK版本的一些安全文件进行覆盖,经过尝试并未生效,最终是因为我使用的JDK8版本,该版本的配置更加简洁,修改参数即可;

(4)使用7-Zip-Jbinding解压缩时含密码的文件时,若密码失败它也不会提示解压缩失败或者密码错误(貌似在解压缩rar格式时,针对于加密了文件名称那一类时会抛出异常),所以再判断解压缩是否成功时,紧紧依靠程序不抛异常是不够的;

(5)使用7-Zip-Jbinding时,若在程序中已经加载了相关的动态链接库后,该文件不能再在Junit的程序中验证,否则会抛出异常

4. 解决方案

在经过大量的压缩包样本的测试验证后,也做了多种程序代码上的解压缩兼容程序,最终使用的还是“7-Zip-Jbinding”组件,并且摒弃了不同的压缩包格式使用不同的组件的方式,统一使用最不看好的“7-Zip-Jbinding”它,因为最终使用它后所有了所有的问题,所以上述各个问题的解决方案,见此处的附件下载。

(1)zip4j解压缩的密码报错问题?

在Java中使用zip4j无法成功解压缩文件,而使用电脑里的解压缩软件就可以的情况,所以起初我使用了“7-Zip-Jbinding”兜底,即解压失败后,再使用“7-Zip-Jbinding”解压,即可解决。说白点,这种情况出现后zip4j无法解压,但“7-Zip-Jbinding”可以成功解压。

(2)zip4j解压缩的乱码问题?

因为在使用“7-Zip-Jbinding”的代码来解析压缩包时,并未设置解析的压缩包文件格式(传递处理格式为空,它自动判断),也未曾设置解压缩文件的编码,为什么它不乱码呢,实际全部在Windows平台上时全部解压缩正常,但是放置在Linux上运行时还是出现了乱码的清空,但是乱码属于比较“正规”的乱码,最终经过debug代码后完美的解决。

所以,zip4j的两个问题加在一起,最终做出的选择是放弃了zip4j,遇到zip格式时,一律也使用“7-Zip-Jbinding”。

(3)使用Apache Commons Compress项目解压一些7z格式的文件时,报密码的复杂度过高时的问题解决方案如下:

image.png

说明:由于需要调整JDK的参数配置,我最终觉得还是拉倒吧,对于7z的格式解压缩仍然使用“7-Zip-Jbinding”。

(4)使用7-Zip-Jbinding解压缩时含密码的文件时,若密码等原因导致的解压失败它也不会被视为错误抛出异常堆栈,所以我用到的文件解压成功与否的逻辑是,增加文件夹的判断,使用工具类获取文件夹中所有的文件的总大小,来与源压缩包文件进行对比,若解压缩后的文件夹大小>源压缩包,即视为解压缩成功,否则视为不成功,但是实际上这么做并不正确,因为针对于小文件时或者某些压缩率不高的文件时,压缩包会存在大于原始文件大小的情况。

最终将判断规则设置为解压缩后的文件夹与0对比,大于0则表示解压缩成功,因为一旦解压缩失败时,要么抛出异常知道失败,要么是生成的解压缩文件大小全部是0。

5)使用“7-Zip-Jbinding”时在Windows下终于世界安静了,但是放Linux上又出现乱码了,也就是为解决平台乱码的情况,debug出来的解决方案,参考代码如下:

image.png

6)使用7-Zip-Jbinding时,若在程序中已经加载了相关的动态链接库后抛出的“另一进程正在使用此文件,进程无法访问”的解决方式为:在使用Junit验证程序时,关闭SpringBoot程序的服务即可,换句话说,即便是此问题不解决,也没啥关系。


 点赞


 发表评论

当前回复:作者

 评论列表


留言区