由unzip解压含有中文文件名变为Unicode代码问题引发的思考


本文出处: http://blog.csdn.net/chaijunkun/article/details/89380527,转载请注明。由于本人不定期会整理相关博文,会对相应内容作出完善。因此强烈建议在原始出处查看此文。

问题描述

一个zip包,里面有文件名包含中文,解压出来发现变成了“井号”+“U”+十六进制的表达形式,算不上是乱码,但文件名变了,这是无法接受的。于是开始了查找问题原因的过程。

项目背景

随着前端技术的发展,越来越多的前端工程师采用ejs、scss等技术实现UI开发。如果Java技术栈的工程师想要使用该静态模板(velocity或者freemarker,或者jsp),需要前端工程师对其进行编译,将其静态化(其中还涉及js、css编译后上传至CDN)后才可使用。

在开发实践中,前端工程师通过本地开启http服务(基于koa、express结合webpack等框架)来对页面进行调试。正值公司的云平台改版,本来耗时繁琐的编译、上传操作就想接入到该平台。这样,对于前端工程师,只关注于本地调试开发。对于Java工程师,只关注静态页。中间转换的过程交给云平台自己完成就行了。

分析运行环境

云平台的工作流水线大致为:

  1. 编译以及静态资源上传,打包(一个项目中会有很多页面)
  2. 将打好的包上传到统一的存储系统
  3. 将之前编译的版本部署到负载机器上(实际是发送指令,负载机从存储系统中按版本下载指定的包文件并进行解压部署)
    注:本流水线各个环节均工作在Linux系统下(CentOS 6.9/7.3)。

回到一开始我们遇到的问题。我们在最后一步解压部署时发现,解压出来的中文文件名被改变了。然后我随便找了一个文件:
它的文件名是这样的:#u9996#u9875-2019.html

直觉告诉我这个不是乱码,看着又很眼熟,然后就打开了常用的小工具网站:http://www.bejson.com/convert/unicode_chinese/

把这个文件名贴进去,然后将“井号”改成"反斜杠"(“\”),然后点击“Unicode转中文”。果然,内容变成了:“首页-2019.html”。这说明,原本中文的文件名被变成了十六进制表示的Unicode代码。

问题找到了,按照下面的步骤进行排查:

  1. 根据日志,将存储系统中的包下载下来。在Windows和Mac下尝试打开查看,都没有问题,说明打包本身没有问题;
  2. 登录目标负载机,将压缩包使用unzip命令进行解压,文件名正常;

因为解压功能不仅可以通过unzip来实现,很多工具或者编程语言都支持zip解压,于是询问运维人员如何实现的解压功能。后来运维工程师发给我如下命令:

 salt-call cmd.run "unzip 带版本的压缩包.zip"

原来使用的是saltstack(一个基于python的自动化运维管理平台)的salt-call命令。于是我复用上述命令进行解压,问题得到了复现。不过解压的核心命令和我本地直接执行的命令并无明显的差别,分析导致该现象的原因应该是环境问题。

于是我在目标负载机上分别执行了

env

salt-call cmd.run "env"

这样就能在不同的上下文环境中显示系统环境变量。经过比对,发现了一些不同。
在直接解压的环境中,关于语言、地区的系统环境变量只有一个:

LANG=en_US.UTF-8

而在salt-call环境下,相关系统变量有这些:

LC_PAPER=C
LC_ADDRESS=C
LC_MONETARY=C
LC_TELEPHONE=C
LC_MESSAGES=C
LC_COLLATE=C
LC_IDENTIFICATION=C
LC_MEASUREMENT=C
LC_CTYPE=C
LC_TIME=C
LC_NAME=C
LANG=en_US.UTF-8

复现问题

为了复现上述问题,我在直接解压的环境中试图将LANG环境变量抹掉,看看会发生什么:

export LANG=

然后用同样的解压命令对压缩包进行解压,果然,文件名里的中文字符全都变成了Unicode代码。

#U8ba2#U5355#U7ba1#U7406#U2014#U7b5b#U9009#U6761#U4ef6.html
#U8ba2#U5355#U7ba1#U7406#U2014#U8ba2#U5355#U5217#U8868.html
#U8ba2#U5355#U7ba1#U7406#U2014#U8ba2#U5355#U8be6#U60c5.html

解决问题

问题原因找到了:unzip命令会获取系统中的语言设置,如果压缩包中的文件名字符属于该字符集下,则使用该字符集;如果文件名字符不属于该字符集下,则采用Unicode代码方式表示,由于文件名中不允许出现“反斜杠”(“\”)这类字符,稳妥起见,会将该字符转换为“井号”(#)。(后来经过实验证实,是LC_CTYPE环境变量导致的该问题)

解决方法:在salt-call代码中,实际执行解压操作之前,设置一个环境变量即可:

salt-call cmd.run "export LC_ALL=en_US.UTF-8 ; unzip 带版本的压缩包.zip"

设置LC_ALL环境变量的好处是:不管LC_*和LANG变量设置的是什么,一旦发现有环境变量LC_ALL,则会用一致使用LC_ALL的设置。

扩展阅读

以下内容摘录自参考文献:

locale把按照所涉及到的文化传统的各个方面分成12个大类,这12个大类分别是:
1、语言符号及其分类(LC_CTYPE)

2、数字(LC_NUMERIC)

3、比较和排序习惯(LC_COLLATE)

4、时间显示格式(LC_TIME)

5、货币单位(LC_MONETARY)

6、信息主要是提示信息,错误信息, 状态信息, 标题, 标签, 按钮和菜单等(LC_MESSAGES)

7、姓名书写方式(LC_NAME)

8、地址书写方式(LC_ADDRESS)

9、电话号码书写方式(LC_TELEPHONE)

10、度量衡表达方式(LC_MEASUREMENT)

11、默认纸张尺寸大小(LC_PAPER)

12、对locale自身包含信息的概述(LC_IDENTIFICATION)。

其中,与中文输入关系最密切的就是 LC_CTYPE, LC_CTYPE 规定了系统内有效的字符以及这些字符的分类,诸如什么是大写字母,小写字母,大小写转换,标点符号、可打印字符和其他的字符属性等方面。而locale定 义zh_CN中最最重要的一项就是定义了汉字(Class “hanzi”)这一个大类,当然也是用Unicode描述的,这就让中文字符在Linux系统中成为合法的有效字符,而且不论它们是用什么字符集编码 的。

设定locale就是设定12大类的locale分类属性,即 12个LC_*。除了这12个变量可以设定以外,为了简便起见,还有两个变量:LC_ALL和LANG。它们之间有一个优先级的关系:

LC_ALL>LC_*>LANG

可以这么说,LC_ALL是最上级设定或者强制设定,而LANG是默认设定值。

参考文献:[1]freeners.关于locale国际化与本土化的设定[EB/OL].http://blog.chinaunix.net/uid-21269292-id-444559.html,2009-06-26.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 如果使用 `unzip` 命令解压缩文件时,中文文件名出现了乱码,可能是因为默认情况下 `unzip` 不支持 UTF-8 编码。 为了解决这个问题,您可以使用 `-O` 参数指定字符集,例如: ``` unzip -O CP936 archive.zip ``` 其中,`CP936` 是简体中文的字符集编码,您可以根据需要使用不同的字符集。 如果您不确定应该使用哪个字符集,您可以尝试使用 `-O UTF8` 参数,这可能会解决中文文件名乱码问题。 ### 回答2: 当我们使用unzip命令解压包含中文文件名的文件时,可能会遇到乱码问题。这是因为在解压过程中,unzip默认使用的字符编码是ASCII,无法正确识别和显示中文字符。 为了解决这个问题,我们可以通过指定字符编码来解决乱码问题。常见的字符编码有utf-8、gbk等。具体操作如下: 1. 首先,我们需要确认我们的中文文件名的字符编码。可以通过使用命令"file -i 文件名"来查看文件的编码类型。 2. 然后,使用unzip命令解压文件,并通过添加参数"-O 字符编码"来指定字符编码。例如,如果我们的文件编码是utf-8,我们可以使用命令"unzip -O utf-8 文件名.zip"来解压文件。 这样,unzip命令会使用指定的字符编码来解析文件名,从而正确地显示中文字符。这种方法适用于大多数情况下的乱码问题。 如果仍然无法正确显示中文文件名,可能是由于文件本身的问题,导致其编码无法被正确识别。这种情况下,我们可以尝试使用其他工具来解压文件,如7-Zip等。这些工具通常会自动识别文件的编码,并正确显示中文文件名。 总之,通过指定正确的字符编码,我们可以解决unzip解压中文文件名乱码的问题,确保文件名能够正确显示。 ### 回答3: 当我们使用unzip命令解压含有中文文件名的压缩文件时,可能会遇到中文文件名乱码的问题。这是因为unzip命令默认使用的字符编码方式是ASCII编码,而中文字符使用的是Unicode编码。为了解决这个问题,我们可以使用以下两种方法: 方法一是通过指定字符编码方式来解决。我们可以使用unzip命令的参数“-O CP936”来指定字符编码方式为CP936(即GB2312或GBK编码)。例如,我们可以使用以下命令来解压一个压缩文件并指定字符编码方式为CP936: unzip -O CP936 filename.zip 方法二是更改系统环境变量,将字符编码方式默认设置为UTF-8。这样,在使用unzip命令解压文件时,会自动使用UTF-8编码来处理文件名,从而避免中文文件名乱码的问题。具体操作如下: 1. 打开终端窗口,并在命令行中输入以下命令: export UNZIP="-O UTF-8" 2. 然后,我们就可以使用unzip命令来解压文件了,例如: unzip filename.zip 通过以上两种方法的任意一种,我们都可以解决unzip解压中文文件名乱码的问题,确保能正确显示和处理中文文件名

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值