• 解决rubyzip使用中遭遇到的中文文件名称乱码问题


        最近程序中需要用到rubyzip这个gem进行解压缩和压缩,于是就遇到了中文文件名变成乱码的问题。

        首先,使用rubyzip解压缩zip文件,代码参照官网的示例很简单

    def unzip(zip_file, dest_dir)    
        Zip::File.open zip_file do |zf|  
          zf.each do |e|          
            path = File.join dest_dir, e.name
            FileUtils.mkdir_p File.dirname(path)  
            zf.extract(e, path) { true }  
          end  
        end  
      end 

    发现中文文件名乱码后,看文档发现只需在方法开始加上 ,

    Zip.force_entry_names_encoding = 'GBK'

    经过测试果然解决问题。

    应用里还需要生成zip压缩包,这里就不贴代码了,完全采用官网的示例即可,这次仔细看了说明,在其中加上下面这行即可顺利生成包含中文文件名的zip压缩包

    Zip.unicode_names = true
    好,现在压缩解压缩代码都完成了,可是接下来问题来了,用自己的代码解压缩自己打包的zip文件,又出现了中文文件名乱码问题!
    经研究发现,一开始的zip包是在windows下打包的,中文文件名编码为gb18030,程序打包的zip文件,中文文件名的编码是UTF-8,在windows下打开解压都没有问题,但是由于解压代码中固定设置为GBK,所以解压自己打包的zip就再次出现乱码现象。
    多方搜索,仔细看文档甚至代码,都没有好的解决方案,不能自适应编码是不能接受的。没办法只能自己解决编码探测问题。
    在gems网站找到2个编码探测的gem一个是纯ruby编码的 ’rchardet‘,另一个是依赖ICU库的 'charlock_holmes', 经测试,两个库都可以完成任务,但是'charlock_holmes' 要比 ’rchardet' 快上一个量级。
    开始,采用每个文件名探测一次的方式,结果很不理想,误报率较高,而且置信度维持低水平,尤其charlock_holmes',经常把中文编码探测为日文Shift_JIS。后改为联合所有文件名为一个字符串在进行探测,发现置信度大幅度提升,基本已经满足需要。
    因为GB18030编码足够空间,所以如果探测到不是ASCII编码,就一律转为GB18030,经测试完美解决了我的问题。
    附上修改后的代码:
    def unzip(zip_file, dest_dir)    
        file_encoding = detect_encoding_v2 zip_file
    
        Zip::File.open zip_file do |zf|  
          zf.each do |e|          
            name = e.name                
            name = name.encode('GB18030', file_encoding) if file_encoding != 'ASCII'
            path = File.join dest_dir, name
            FileUtils.mkdir_p File.dirname(path)  
            zf.extract(e, path) { true }  
          end  
        end  
      end 
    
    def detect_encoding_v2(zip_file)   
        require 'charlock_holmes' 
        names = []
        Zip::File.open zip_file do |zf|  
          zf.each do |e|
            name = e.name
            names << e.name
          end
        end
        ss = names.join
        cd = CharlockHolmes::EncodingDetector.detect(ss)
        syscoding = name.encoding.to_s.upcase
        coding = cd[:encoding].upcase
    
        if coding=='ASCII' && syscoding!='ASCII'
          coding = 'GB18030'
        end
       
        return coding
      end
    View Code
     
  • 相关阅读:
    Spring快速开启计划任务
    一张图告诉你什么是系统架构师
    一张图搞清楚Java异常机制
    Spring Cloud配置中心内容加密
    Spring Cloud配置中心高可用搭建
    Spring Cloud动态刷新配置信息
    Spring Boot实现热部署
    Spring Boot集成Mybatis双数据源
    (1)python tkinter-窗体
    (1)html基础
  • 原文地址:https://www.cnblogs.com/dajianshi/p/14577342.html
Copyright © 2020-2023  润新知