jszip和pizzip中文乱码的解决方案

jszip中文乱码的解决方案

jszip官方文档地址:https://stuk.github.io/jszip/

1、问题分析

在JavaScript中需要用到对Zip压缩包进行操作时,我们往往会使用jszip对压缩包进行编辑。

但是,当我们使用jszip来读取包含中文名的文件时,文件名会出现乱码的情况。

下面的示例中我们使用jszip3.0版本来进行读取testZip.zip压缩包,压缩包中有三个中文的docx文件。

import JSZip from 'jszip'
import JSZipUtils from 'jszip-utils'

export function useJSZip() {
  JSZipUtils.getBinaryContent('../../public/testZip.zip', function (err, data) {
    if (err) {
      throw err
    }

    JSZip.loadAsync(data).then(function (zip) {
      console.log(zip.files)
      /* 
      Ђ• DOCX ΄••1.docx
      Ђ• DOCX ΄••2.docx
      Ђ• DOCX ΄••3.docx
      */
    })
  })
}

代码中我们看到,本应该为新建 DOCX 文档1.docx的文件名变为了乱码,这种情况下使用file-saver进行保存时会出现问题。

通过查看jszip官方文档,我们可以看到jszip在读取文件名时对文件名默认使用UTF-8的文件名解码。

一般中文压缩文件中的文件名都以gbk形式进行编码,而jszip在读取压缩包时,使用UTF-8解码gbk编码的文件名,这时就导致我们的文件名出现了乱码。

2、解决思路

通过上面的问题分析我们可以有两个解决思路。

1、第一个思路可以从jszip的编码上进行解决,参考官方文档,如果我们使用的是jszip3.0及以上的版本我们可以在loadAsync方法的options参数中自定义解码方法,这样jszip在读取文件名解码时会以回调函数的形式执行并接受我们自定义的解码器所传入的文件名。

当然如果我们是想配合docxtemplater进行模板文档功能的实现时,jszip3.0并不能满足需求,因为docxtemplater仅仅支持到jszip2.0的版本和docxtemplater基于jszip2.0封装的pizzip。在jszip2.0中我们需要使用load方法来读取文件,并在里面自定义解码器。pizzip是官方基于jszip2.0进行封装的更适合docxtemplater算法的一个包,解决方法和使用方法与jszip2.0相同。

2、第二个思路是在压缩包文件本身进行解决,将压缩包的中文编码改为utf-8即可。

3、解决方法

1、对于自定义编码,我们可以使用第三方解码器iconv-lite来实现gbk的解码。

# 安装iconv-lite
npm i iconv-lite --save
# 在浏览器中运行时可能会报错缺少buffer包,如果出错使用下面代码安装
npm i buffer -D

jszip3.0解决方法

import JSZip from 'jszip'
import JSZipUtils from 'jszip-utils'
import iconv from 'iconv-lite'

export function useJSZip() {
  JSZipUtils.getBinaryContent('../../public/testZip.zip', function (err, data) {
    if (err) {
      throw err
    }
    // 指定options编码器
    JSZip.loadAsync(data, {
      decodeFileName: function (bytes) {
        // 使用iconv-lite解码
        return iconv.decode(bytes, 'gbk')
      },
    }).then(function (zip) {
      console.log(zip.files)
      /* 
      新建 DOCX 文档1.docx
      新建 DOCX 文档2.docx
      新建 DOCX 文档3.docx
      */
    })
  })
}

jszip2.0解决方法

import JSZip from 'jszip'
import JSZipUtils from 'jszip-utils'
import iconv from 'iconv-lite'

export function renderZip() {
  JSZipUtils.getBinaryContent(
    '../../public/testZip.zip',
    function (err, data) {
      if (err) {
        throw err // or handle err
      }

      const zip = new JSZip()

      zip.load(data, {
        decodeFileName: function (bytes) {
          // 使用iconv-lite库来解码gbk
          return iconv.decode(bytes, 'gbk')
        },
      })

      console.log(zip.files)
      /* 
      新建 DOCX 文档1.docx
      新建 DOCX 文档2.docx
      新建 DOCX 文档3.docx
      */
    }
  )
}

pizzip解决方法

import PizZip from 'pizzip'
import PizZipUtils from 'pizzip/utils/index.js'
import iconv from 'iconv-lite'

export function renderZip() {
  PizZipUtils.getBinaryContent(
    '../../public/testZip.zip',
    function (err, data) {
      if (err) {
        throw err // or handle err
      }

      const zip = new PizZip()

      zip.load(data, {
        decodeFileName: function (bytes) {
          // 使用iconv-lite库来解码gbk
          return iconv.decode(bytes, 'gbk')
        },
      })

      console.log(zip.files)
      /* 
      新建 DOCX 文档1.docx
      新建 DOCX 文档2.docx
      新建 DOCX 文档3.docx
      */
    }
  )
}

注意

  • 配合docxtempater时推荐采用官方封装的pizzip进行,可以使用jszip2.0,但不能使用jszip3.0及以上版本,因为高版本jszip并没有被docxtemplater适配支持。
  • 使用jszip2.0pizzip时调用函数的方法基本一致,但是导入的方法不一致,jszip在浏览器端读取本地文件时需要单独安装jszip-utils包进行二进制数据的读取。而pizzip将读取二进制文件的方法集成到包中,只需要导入pizzip中的pizzip/utils/index.js即可。
  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值