关于Java解压文件的一些坑及经验分享

就在本周, 测试人员找到我说现上的需求文档(zip格式的)无法预览了, 让我帮忙看看怎么回事。

这个功能也并不是我做的, 于是我便先看看线上日志有没有什么错误,果不其然, 后台果然报错了。

java.lang.IllegalArgumentException:MALFORMED

at java.util.zip.ZipCoder.toString(ZipCoder.toString:58)

...

异常大致是这样,前台无法预览需求文档的原因是该zip文件解压失败了。

首先网上查了下这个异常的原因, 都说是因为编码的问题, 要求将UTF-8改成GBK就可以了。

然后定位代码, 看到有一个方法:unzip()public static void unzip(File zipFile, String descDir) {    try {

File pathFile = new File(descDir);        if (!pathFile.exists()) {

pathFile.mkdirs();

}

ZipFile zip = getZipFile(zipFile);        for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) {

ZipEntry entry = (ZipEntry) entries.nextElement();

String zipEntryName = entry.getName();            if (StringUtils.isNotBlank(pre)) {

zipEntryName = zipEntryName.substring(pre.length());

}

InputStream in = zip.getInputStream(entry);

String outPath = (descDir + "/" + zipEntryName).replaceAll("\\*", "/");

;            //判断路径是否存在,不存在则创建文件路径

File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));            if (!file.exists()) {

file.mkdirs();

}            //判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压

if (new File(outPath).isDirectory()) {                continue;

}            //输出文件路径信息

LOG.info("解压文件的当前路径为:{}", outPath);

OutputStream out = new FileOutputStream(outPath);

IOUtils.copy(in, out);

in.close();

out.close();

}

zip.close();

LOG.info("******************解压完毕********************");

} catch (Exception e) {

LOG.error("[unzip] 解压zip文件出错", e);

}

}private static ZipFile getZipFile(File zipFile) throws Exception {

ZipFile zip = new ZipFile(zipFile, Charset.forName("UTF-8"));

Enumeration entries = zip.entries();    while (entries.hasMoreElements()) {        try {

entries.nextElement();

zip.close();

zip = new ZipFile(zipFile, Charset.forName("UTF-8"));            return zip;

} catch (Exception e) {

zip = new ZipFile(zipFile, Charset.forName("GBK"));            return zip;

}

}    return zip;

}

于是便将线上的zip文件down下来 然后本地调试下, 发现在第9行中抛出了异常, 如下代码:ZipEntry entry = (ZipEntry) entries.nextElement();

再由最开始的异常日志找到ZipCoder中的58行:String toString(byte[] ba, int length) {

CharsetDecoder cd = decoder().reset();    int len = (int)(length * cd.maxCharsPerByte());    char[] ca = new char[len];    if (len == 0)        return new String(ca);    // UTF-8 only for now. Other ArrayDeocder only handles

// CodingErrorAction.REPLACE mode. ZipCoder uses

// REPORT mode.

if (isUTF8 && cd instanceof ArrayDecoder) {        int clen = ((ArrayDecoder)cd).decode(ba, 0, length, ca);        if (clen == -1)    // malformed

throw new IllegalArgumentException("MALFORMED");        return new String(ca, 0, clen);

}

ByteBuffer bb = ByteBuffer.wrap(ba, 0, length);

CharBuffer cb = CharBuffer.wrap(ca);

CoderResult cr = cd.decode(bb, cb, true);    if (!cr.isUnderflow())        throw new IllegalArgumentException(cr.toString());

cr = cd.flush(cb);    if (!cr.isUnderflow())        throw new IllegalArgumentException(cr.toString());    return new String(ca, 0, cb.position());

}

这里只有UTF-8才会进入if逻辑才会抛错?果然如网上所说, 将编码格式改为GBK即可。

ZipCoder这个类似src.zip包中的, 既然这里做了check当然会有它的道理, 单纯的改为GBK来解决这个bug显然是不合理的。

于是便要换种思路了, 线上有些zip是仍然可以预览的。 我将线上的zip文件解压后, 在自己电脑重新打个包(我用的是好压), 然后又运行了上述代码, 竟然解压成功?? 这是为什么? 于是上网上找了一下, 果然找到了答案:Windows 压缩的时候使用的是系统的编码 GB2312,而 Mac 系统默认的编码是 UTF-8,于是出现了乱码。

最后去问了上传的同事, 他是在Windows下用的winRar上传的(看来不同的解压工具还不同)。

好了, 问题基本定位到了, 这里就要想着怎么解决了。

又是一通找, 终于:Apache commons-compress 解压 zip 文件是件很幸福的事,可以解决 zip 包中文件名有中文时跨平台的乱码问题,不管文件是在 Windows 压缩的还是在 Mac,Linux 压缩的,解压后都没有再出现乱码问题了。

看到这里基本上问题就要解决了, 于是开始使用apache的commons-compress了, 下面直接上代码, 代码是基于上面代码进行改造的:

首先引入pom文件:

org.apache.commons

commons-compress

1.8.1public static void main(String[] args) throws Exception{

String path = "C:\\Users\\Isuzu\\Desktop\\test.zip";

unzip(new File(path), "D:\\data",);

}public static void unzip(File zipFile, String descDir) {    try (ZipArchiveInputStream inputStream = getZipFile(zipFile)) {

File pathFile = new File(descDir);        if (!pathFile.exists()) {

pathFile.mkdirs();

}

ZipArchiveEntry entry = null;        while ((entry = inputStream.getNextZipEntry()) != null) {            if (entry.isDirectory()) {

File directory = new File(descDir, entry.getName());

directory.mkdirs();

} else {

OutputStream os = null;                try {

os = new BufferedOutputStream(new FileOutputStream(new File(descDir, entry.getName())));                    //输出文件路径信息

LOG.info("解压文件的当前路径为:{}", descDir + entry.getName());

IOUtils.copy(inputStream, os);

} finally {

IOUtils.closeQuietly(os);

}

}

}        final File[] files = pathFile.listFiles();        if (files != null && files.length == 1 && files[0].isDirectory()) {            // 说明只有一个文件夹

FileUtils.copyDirectory(files[0], pathFile);            //免得删除错误, 删除的文件必须在/data/demand/目录下。

boolean isValid = files[0].getPath().contains("/data/www/");            if (isValid) {

FileUtils.forceDelete(files[0]);

}

}

LOG.info("******************解压完毕********************");

} catch (Exception e) {

LOG.error("[unzip] 解压zip文件出错", e);

}

}private static ZipArchiveInputStream getZipFile(File zipFile) throws Exception {    return new ZipArchiveInputStream(new BufferedInputStream(new FileInputStream(zipFile)));

}

到了这里就大功告成了, 原先自己遇到这个问题时百度了一圈, 解决方案大都是改编码格式为GBK, 但那也只是治标不治本的方法, 解压的坑就讲这么多, 后续有新的坑还会继续总结出来的。

java zip malformed_关于Java解压文件的一些坑及经验分享(MALFORMED异常)相关推荐

  1. Java解压文件的一些坑及经验分享(MALFORMED异常)

    一.错误如下: java.lang.IllegalArgumentException: MALFORMEDat java.util.zip.ZipCoder.toString(ZipCoder.jav ...

  2. java zip加密压缩_Java解压和压缩带密码的zip文件过程详解

    前言 JDK自带的ZIP操作接口(java.util.zip包,请参看文章末尾的博客链接)并不支持密码,甚至也不支持中文文件名. 为了解决ZIP压缩文件的密码问题,在网上搜索良久,终于找到了winzi ...

  3. Java解压文件Zip,War,Tar,TarGz格式

    Java压缩和解压缩 压缩和解压缩依赖 关于Java解压Zip文件的java.lang.IllegalArgumentException:MALFORMED报错问题. 解压缩代码 Zip解压缩 War ...

  4. 使用java程序下载远程zip文件并解压文件( 带注释解释代码)

    带注释解释代码 package com.zcl.Test;import java.io.*; import java.net.HttpURLConnection; import java.net.So ...

  5. java model 中文乱码_Java解压zip 解决编码和中文乱码问题

    项目由GBK转成UTF-8 遇到原有解析zip发现中文文件名称乱码问题 net.lingala.zip4j zip4j 1.3.2 package com.multek.ebuy.utils; imp ...

  6. java解压文件、复制文件、删除文件代码示例

    文章目录 删除文件: 创建目录 拷贝文件 解压zip文件 解压文件时,可以采用多线程的方式,下面上代码: 创建类 @Slf4j public class FileOperation {private ...

  7. java文件解压文件_java 文件解压缩

    直接上代码: import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; ...

  8. java代码实现解压文件_Java压缩/解压文件的实现代码

    用java压缩/解压文件: import java.io.*; import java.awt.*; import java.awt.event.*; import java.util.*; impo ...

  9. java实现 zip rar 7z 压缩包解压

    1.7z和rar需要引入maven依赖,zip使用java自带的 <!-- 7z解压依赖 --><dependency><groupId>org.apache.co ...

最新文章

  1. Java数据结构与算法(八)-二叉树
  2. java按行读取txt文件内容_对txt文件中的内容进行排序
  3. [bzoj 4869] [六省联考2017] 相逢是问候
  4. JS 运行、复制、另存为 代码。
  5. spring里restTemplate向目的URL发送post请求
  6. 181006扇贝有道每日一句
  7. 基于matlab指纹识别论文,基于MATLAB的指纹识别算法.doc
  8. 2021年A特种设备相关管理(电梯)考试题库及A特种设备相关管理(电梯)证考试
  9. 没有更改计算机日期权限,修改电脑时间_修改电脑时间没有权限
  10. PS—制作 抖音 图标
  11. 百度网盘下载速度太慢,有什么办法可以提高下载速度?
  12. Hexo博客标题栏背景颜色设置美化
  13. 计算机类知识期刊,计算机类期刊投稿
  14. python+微信+腾讯智能闲聊
  15. K-Means聚类实验报告实例
  16. python名字的来历_你知道Python的由来吗
  17. 如何判断是否受到DDOS攻击?被攻击该如何解决?
  18. CPP-week thirteen
  19. 《Adobe Photoshop CC经典教程》—第1课1.4节在Photoshop中还原操作
  20. 华为金融大数据解决方案

热门文章

  1. java格式错误什么意思_java.io.IOException可能的原因是什么:“文件名,目录名或卷标语法不正确”...
  2. python文件中环境声明_Python环境构建
  3. dsc linux 软件安装_linux – 安装dsc21时出错:“dsc21:取决于:cassandra(= 2.1.8),但要安装2.2.0”...
  4. C++设计模式--单例模式(Singleton)及单例通用模板
  5. 【已解决】Navicat 远程连接 Linux服务器上的MySQL数据库
  6. 2.4.1 算术逻辑单元ALU与加法器(串行加法器、并行加法器、全加器)
  7. 3.1.4 操作系统之内存的分配与回收
  8. Qt5 使用 #pragma 加载 lib 文件的注意事项
  9. php文本教学,php中文本操作的类
  10. MTK Read/Write Ethernet Mac Addrees from Kernel NvRAM Patch