• ZipInputStream解压报错java.lang.IllegalArgumentException: MALFORMED


    背景

    使用jdk自带的zip工具ZipInputStream,去读取使用winrar在中文windows制作出来的zip文件报错。

    Exception in thread "main" java.lang.IllegalArgumentException: MALFORMED
    	at java.util.zip.ZipCoder.toString(ZipCoder.java:58)
    	at java.util.zip.ZipInputStream.readLOC(ZipInputStream.java:300)
    	at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:122)
    
    • 1
    • 2
    • 3
    • 4

    从报错信息“MALFORMED”,第一反应就是文件名解码失败,因为使用winrar制作的zip肯定是符合zip标准格式的,唯一有疑点的就是文件名是中文,然后存储时的编码和解码是的编码不一致。
    查看ZipInputStream构造函数可以传编码,因此使用
    new ZipInputStream(new FileInputStream(zipFile),Charset.forName(“GBK”))尝试解码,结果成功,因此确认报错由文件名解码失败导致。

    改进

    本系统服务全球,并不是所有人都是用的是中文操作系统,ZIP文件的编码格式并不是唯一的,因此需要找到更智能zip工具替代ZipInputStream。
    以前做压缩算法时,有听说过Apache的commons compress,因此尝试一下,该工具是否能够自动识别编码,做到对文件名的正确解压。
    尝试使用ZipArchiveInputStream,在不传编码格式的情况下,能够正常解码出文件名。好奇它是如何做到的,因此翻阅了相关,文档及源码结论如下:

    1. 使用传入的编码尝试解码文件名,解码器中对于无法识别的字节使用“?”替代(对比JDK直接报错,该设计,作为开发应该更赞同这种方式吧)。
      在这里插入图片描述
    2. 尝试对额外的文件名字段,使用UTF-8解码,该值优先级更高,只要能解码出非空的值,就优先使用该文件名。
      在这里插入图片描述
      上述两处代码跟着ZipArchiveInputStream的getNextZipEntry()方法就可以跟踪到。

    关于上述第2点的说明:
    可以阅读https://commons.apache.org/proper/commons-compress/zip.html中的Encoding章节。
    主要内容如下,
    1、最开始zip使用CodePage 437作为文件名的编码,这个字符集太小无法满足全球所有国家的使用
    2、然后不同的打包工具开始尝试使用不同的方式来支持不同文字的文件名。有一种方式就是使用传入的编码对文件名进行编码并存入到zip规定的文件名字段中,并使用zip定义的扩展字段存储,使用UTF-8编码的文件名。当然并不是所有的工具都会这么干,所以commons compress也只是尝试使用该字段解码文件名,如果为空,还是会使用文件名的标准字段解码出的文件名。

  • 相关阅读:
    架构与思维:熔断限流的一些使用场景
    java计算机毕业设计社区图书馆借阅管理系统源程序+mysql+系统+lw文档+远程调试
    Tomcat
    什么是行内元素的盒模型
    揭开ChatGPT面纱(3):使用OpenAI进行文本情感分析(embeddings接口)
    HarmonyOS真机调试报错:INSTALL_PARSE_FAILED_USESDK_ERROR处理
    JS中的链
    心理学杂文
    C++并发与多线程笔记六:单例模式下的数据共享
    【附源码】Python计算机毕业设计社区论坛
  • 原文地址:https://blog.csdn.net/shuxiaohua/article/details/134275099