java解压ZIP 解决中文乱码 (GBK和UTF-8)

java解压ZIP 解决中文乱码 (GBK和UTF-8)

本文CSDN地址

工具使用 : zip4j

GitHub : zip4j

版本 : 2.2.8

Maven :


<dependency>
    <groupId>net.lingala.zip4j</groupId>
    <artifactId>zip4j</artifactId>
    <version>2.2.8</version>
</dependency>

ZIP解压现状

ZIP格式在不同平台上使用不同软件压缩,大致结果为两类:
1. Windows下使用WinRAR、好压、快压、百度压缩等工具压缩的文件
    特点:文件名为GBK编码
2. 使用Linux、MacOS等系统压缩的zip文件
    特点:文件名为UTF-8编码

过往解决方案

通过指定解压时的文件名编码类型来解决,最简单粗暴的就是

ZipFile zip = new ZipFile(dest);
//直接指定GBK,反正大多数人用win操作
zip.setFileNameCharset("GBK");
zip.extractAll(Constants.GOODS_ITEM_IMG_PATH);

但是现在用macOS办公的人越来越多,这种写法已经不满足需求了

新解决方案

通过阅读ZIP的协议文档,我们可以发现,Info-ZIP Unicode Path Extra Field (0x7075)
这个额外信息可以解决我们的问题,据笔者测试,WinRAR和百度压缩等使用GBK作为文件编码的压缩软件,
在这个区域会记录文件名的UTF-8编码的名称,但是因为这个字段不是必要字段,文件名使用UTF-8编码的
MacOS归档、Deepin归档等软件不会填充这个信息。

解决方案代码

     String extractAll(MultipartFile file) throws Exception { 
            String path = RECEIVABLE_SHEET_PATH;
             if(!new File(path).mkdirs()) {
                 return "上传文件失败,无法创建临时文件夹";
             }
             File dest = new File(path + "/"+file.getOriginalFilename());
             file.transferTo(dest);
    
             /* 解压 */
             try {
                ZipFile zip = new ZipFile(dest);
                
                zip.setCharset(Charset.forName("utf-8"));
                 System.out.println("begin unpack zip file....");
                 
                zip.getFileHeaders().forEach(v->{
                    String extractedFile = getFileNameFromExtraData(v);
                    try {
                        zip.extractFile(v, path,extractedFile);
                    } catch (ZipException e) {
                        System.out.println("解压失败 :"+extractedFile);
                        e.printStackTrace();
                        return;
                    }
                    System.out.println("解压成功 :"+extractedFile);
                });
                 System.out.println("unpack zip file success");
            } catch (ZipException e) {
                if(!new File(path).mkdirs())
                    return "解压失败";
            }
             return "success";
        }
     
      public static String getFileNameFromExtraData(FileHeader fileHeader) {
              if(fileHeader.getExtraDataRecords()!=null){
                  for (ExtraDataRecord extraDataRecord : fileHeader.getExtraDataRecords()) {
                      long identifier = extraDataRecord.getHeader();
                      if (identifier == 0x7075) {
                          byte[] bytes = extraDataRecord.getData();
                          ByteBuffer buffer = ByteBuffer.wrap(bytes);
                          byte version = buffer.get();
                          assert (version == 1);
                          int crc32 = buffer.getInt();
                          System.out.println("使用:fileHeader.getExtraDataRecords() ");
                          return new String(bytes, 5, buffer.remaining(), StandardCharsets.UTF_8);
                      }
                  }
              }
              System.out.println("使用:fileHeader.getFileName()");
              return fileHeader.getFileName();
          }

参考ZIP规范资料

Third party mappings commonly used are:

       0x07c8        Macintosh
       0x2605        ZipIt Macintosh
       0x2705        ZipIt Macintosh 1.3.5+
       0x2805        ZipIt Macintosh 1.3.5+
       0x334d        Info-ZIP Macintosh
       0x4341        Acorn/SparkFS
       0x4453        Windows NT security descriptor (binary ACL)
       0x4704        VM/CMS
       0x470f        MVS
       0x4b46        FWKCS MD5 (see below)
       0x4c41        OS/2 access control list (text ACL)
       0x4d49        Info-ZIP OpenVMS
       0x4f4c        Xceed original location extra field
       0x5356        AOS/VS (ACL)
       0x5455        extended timestamp
       0x554e        Xceed unicode extra field
       0x5855        Info-ZIP UNIX (original, also OS/2, NT, etc)
       0x6375        Info-ZIP Unicode Comment Extra Field
       0x6542        BeOS/BeBox
       0x7075        Info-ZIP Unicode Path Extra Field
       0x756e        ASi UNIX
       0x7855        Info-ZIP UNIX (new)
       0xa220        Microsoft Open Packaging Growth Hint
       0xfd4a        SMS/QDOS

-Info-ZIP Unicode Path Extra Field (0x7075):

       Stores the UTF-8 version of the file name field as stored in the
       local header and central directory header. (Last Revision 20070912)

       Value         Size        Description
       -----         ----        -----------
       (UPath) 0x7075        Short       tag for this extra block type ("up")
       TSize         Short       total data size for this block
       Version       1 byte      version of this extra field, currently 1
       NameCRC32     4 bytes     File Name Field CRC32 Checksum
       UnicodeName   Variable    UTF-8 version of the entry File Name

       Currently Version is set to the number 1.  If there is a need
       to change this field, the version will be incremented.  Changes
       may not be backward compatible so this extra field should not be
       used if the version is not recognized.

       The NameCRC32 is the standard zip CRC32 checksum of the File Name
       field in the header.  This is used to verify that the header
       File Name field has not changed since the Unicode Path extra field
       was created.  This can happen if a utility renames the File Name but
       does not update the UTF-8 path extra field.  If the CRC check fails,
       this UTF-8 Path Extra Field should be ignored and the File Name field
       in the header should be used instead.

       The UnicodeName is the UTF-8 version of the contents of the File Name
       field in the header.  As UnicodeName is defined to be UTF-8, no UTF-8
       byte order mark (BOM) is used.  The length of this field is determined
       by subtracting the size of the previous fields from TSize.  If both
       the File Name and Comment fields are UTF-8, the new General Purpose
       Bit Flag, bit 11 (Language encoding flag (EFS)), can be used to
       indicate that both the header File Name and Comment fields are UTF-8
       and, in this case, the Unicode Path and Unicode Comment extra fields
       are not needed and should not be created.  Note that, for backward
       compatibility, bit 11 should only be used if the native character set
       of the paths and comments being zipped up are already in UTF-8. It is
       expected that the same file name storage method, either general
       purpose bit 11 or extra fields, be used in both the Local and Central
       Directory Header for a file.

参考文献

unzip not correct with cjk filename. #45

Garbled chinese character #73

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • 引用: https://blog.csdn.net/IndexMan/article/details/801884...
    lekf123阅读 2,973评论 0 0
  • 作者:crane-yuan 日期:2017-05-02 问题 由于zip格式中并没有指定编码格式,Windows下...
    craneyuan阅读 3,783评论 0 3
  • 简单来说,unicode,gbk和大五码就是编码的值,而utf-8,uft-16之类就是这个值的表现形式.而前面那...
    百里求一阅读 1,140评论 0 2
  • 相信在电脑这个只认识0和1的蠢货世界里编码是个大问题,稍有不慎我们写的东西或做的东西都会变成一个一个小蝌蚪文,也就...
    代码和远方阅读 1,919评论 0 0
  • 这些护肤经验,美容院是不会主动跟你说的 对于护肤大家会不会有这样的困惑:天天喊着护肤,学习了各种方法,使用了各种护...
    adou阿东阅读 170评论 0 0