文档章节

Go如何处理zip中的中文文件名

chai2010
 chai2010
发布于 2013/12/20 11:46
字数 770
阅读 1560
收藏 16
点赞 1
评论 13

Go的标准库已经自带了zip的库.

不过zip包在处理内部文件名时, 默认是utf8编码的. 对于Windows中文用户, 生成和读取zip内部文件名默认是GBK编码的. 因此, 在处理涉及GBK的文件名时需要做一个转换.

Go语言官方的 go.text 子标准库已经支持各种编码, 下面是utf8转GBK的函数:

import "golang.org/x/text/encoding/simplifiedchinese"

func utf8ToGBK(text string) (string, error) {
	dst := make([]byte, len(text)*2)
	tr := simplifiedchinese.GB18030.NewEncoder()
	nDst, _, err := tr.Transform(dst, []byte(text), true)
	if err != nil {
		return text, err
	}
	return string(dst[:nDst]), nil
}

在生成zip文件时, 用 utf8ToGBK 处理文件名:

func main() {
	file, err := os.Create("中文-测试.zip")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	wzip := zip.NewWriter(file)
	defer func() {
		if err := wzip.Close(); err != nil {
			log.Fatal(err)
		}
	}()

	// 压缩文件
	var files = []struct{ Name, Body string }{
		{"11/1/readme.txt", "UTF8 字符串."},
		{"11/1/readme2.txt", "This archive contains some text files."},
		{"汉字/2/gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
		{"11/中文.txt", "中文Get animal handling licence.\nWrite more examples."},
		{"空目录/", ""},
	}
	for _, file := range files {
		name, _ := utf8ToGBK(file.Name) // 文件名转换为 GBK编码
		f, err := wzip.Create(name)
		if err != nil {
			log.Fatal(err)
		}
		_, err = f.Write([]byte(file.Body))
		if err != nil {
			log.Fatal(err)
		}
	}
}

这样就可以生成Windows下带简体中文的文件名压缩文件了.

2014年补充:

其实在新的 zip规范 中, 已经对UTF8编码的文件名提供了支持.

File:    APPNOTE.TXT - .ZIP File Format Specification
Version: 6.3.3

4.4.4 general purpose bit flag: (2 bytes)

Bit 11: Language encoding flag (EFS).  If this bit is set,
	the filename and comment fields for this file
	MUST be encoded using UTF-8. (see APPENDIX D)

具体来说, 在每个文件的头信息的Flags字段的11bit位. 如果该bit位为0则表用本地编码(本地编码是GBK吗?), 如果是1则表示用UTF8编码.

头信息对应zip库的 archive/zip.FileHeader 结构的 Flags 成员:

type FileHeader struct {
	// Name is the name of the file.
	// It must be a relative path: it must not start with a drive
	// letter (e.g. C:) or leading slash, and only forward slashes
	// are allowed.
	Name string

	CreatorVersion     uint16
	ReaderVersion      uint16
	Flags              uint16
	Method             uint16
	ModifiedTime       uint16 // MS-DOS time
	ModifiedDate       uint16 // MS-DOS date
	CRC32              uint32
	CompressedSize     uint32 // deprecated; use CompressedSize64
	UncompressedSize   uint32 // deprecated; use UncompressedSize64
	CompressedSize64   uint64
	UncompressedSize64 uint64
	Extra              []byte
	ExternalAttrs      uint32 // Meaning depends on CreatorVersion
	Comment            string
}

如果想生成UTF8编码的文件名, 可以手工指定该字段:

func main() { file, err := os.Create("中文-测试.zip") if err != nil { log.Fatal(err) } defer file.Close()

wzip := zip.NewWriter(file)
defer func() {
	if err := wzip.Close(); err != nil {
		log.Fatal(err)
	}
}()

// 压缩文件
var files = []struct{ Name, Body string }{
	{"11/1/readme.txt", "UTF8 字符串."},
	{"11/1/readme2.txt", "This archive contains some text files."},
	{"汉字/2/gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
	{"11/中文.txt", "中文Get animal handling licence.\nWrite more examples."},
	{"空目录/", ""},
}
for _, file := range files {
	header := &zip.FileHeader{
		Name:   file.Name,
		Flags:  1 << 11, // 使用utf8编码
		Method: zip.Deflate,
	}
	f, err := wzip.CreateHeader(header)
	if err != nil {
		log.Fatal(err)
	}
	_, err = f.Write([]byte(file.Body))
	if err != nil {
		log.Fatal(err)
	}
}

}

其实, zip.Create 默认应该是假设文件名采用UTF8编码, 这样可以避免不同机器间本地编码不同导致的解码的问题. 针对该修改已经提交了 CL54360043, 目前还不清楚是否能够被接受.

不过比较遗憾的是Win7自带的zip浏览器始终是忽略该字段的(始终用本地编码处理).


https://chai2010.cn/

© 著作权归作者所有

共有 人打赏支持
chai2010

chai2010

粉丝 414
博文 99
码字总数 81410
作品 10
武汉
程序员
加载中

评论(13)

chai2010
chai2010

引用来自“Meteormatt”的评论

Golang 1.9会自动处理了。不需要加Flags了
https://github.com/golang/go/commit/0a3f3e166d702f477863a5260779fa0357c72302
感谢告知
Meteormatt
Meteormatt
Golang 1.9会自动处理了。不需要加Flags了
https://github.com/golang/go/commit/0a3f3e166d702f477863a5260779fa0357c72302
chai2010
chai2010
暂时放弃了 CL, 原因是这个CL强制启用utf8编码, 这样会导致无法生成gbk编码的zip.
我创建了一个issue讨论这个:
https://github.com/golang/go/issues/10741

希望能够增加2个函数, 用于支持任意的本地编码(不仅仅是gbk).
第三方支付接口
第三方支付接口
生成成功,感谢大大!
chai2010
chai2010

引用来自“学习重要”的评论

我說的MSFT員工是Michael S. Kaplan,他的推特:https://twitter.com/michkap

另外MSFT似乎也在改進對UTF-8的zip的支持,雖然XP肯定沒戲:http://support.microsoft.com/kb/2704299/en-us
这个补丁安装上好像没效果...
chai2010
chai2010
Go创建中文zip Windows下乱码的问题, 重新提交了补丁:
https://go-review.googlesource.com/#/c/9381/

不过 win7 的本地zip 解压是有bug的, 不支持utf8的标志位.
这里有个微软的补丁:
http://support.microsoft.com/zh-cn/kb/2704299

但是对中文好像没效果...
woooya
woooya

引用来自“chai2010”的评论

引用来自“doomsplayer”的评论

mahonia就好了

已经有了官方的go.text库, mahonia基本是被淘汰了.

这样啊。。孤陋寡闻了
学习重要
学习重要
我說的MSFT員工是Michael S. Kaplan,他的推特:https://twitter.com/michkap

另外MSFT似乎也在改進對UTF-8的zip的支持,雖然XP肯定沒戲:http://support.microsoft.com/kb/2704299/en-us
学习重要
学习重要

引用来自“chai2010”的评论

引用来自“学习重要”的评论

生成也用UTF-8啊,不然你的zip在除了簡體中文的Windows的所有系統都會亂碼。
不支持UTF-8最大的阻力也就是Windows的自帶zip不支持UTF-8(不知道Windows 8/8.1解決了沒),但是國內誰沒個壓縮軟件啊,用Windows的。

生成的zip文件主要是为了Windows中文环境下打开没有乱码, 不是为了仅仅给Go程序打开的.

正常的程序打開UTF-8的zip都不會亂碼...包括7-zip,WinRAR,WinZip,國產壓縮軟件相信更加不會...

只是MSFT的zip支持是壞的,之前有MSFT員工在msdn blog上吐嘈,現在那個blog被MSFT河蟹了好像。
chai2010
chai2010

引用来自“学习重要”的评论

生成也用UTF-8啊,不然你的zip在除了簡體中文的Windows的所有系統都會亂碼。
不支持UTF-8最大的阻力也就是Windows的自帶zip不支持UTF-8(不知道Windows 8/8.1解決了沒),但是國內誰沒個壓縮軟件啊,用Windows的。

生成的zip文件主要是为了Windows中文环境下打开没有乱码, 不是为了仅仅给Go程序打开的.
请教各位大神,为什么django下载的zip压缩包文件名中包含中文的就乱码啊?

各位朋友们好,我用django写了一个网页,可以下载zip的压缩包文件,但是如果该zip文件名含有中文,比如如果zip文件名是”math.zip”,那么下载的时候显示的文件名也是”math.zip”,但是如果...

qingyuanlu
2015/10/28
347
0
解决下载文件名乱码

今天做文件下载功能模块,发现几个问题。 1. 如果指定的文件名里包含了空格,FireFox就会截取空格前的部分作为默认文件名,IE就会在空格位置通过+号填补 2. 中文字符乱码,准确的是非 ASCII ...

hc_naa
2016/02/19
72
1
Apache Ant包进行ZIP文件压缩

Apache Ant包进行ZIP文件压缩 许多年前就遇到过这种业务,对ZIP标准压缩文件解压。之前写的操作类现在找不到了,最近项目中又要处理这种业务,所以重新写了一个。Java提供了处理ZIP包的API。...

一堆BUG
2012/02/28
0
0
文件打包与解压缩

目录: zip压缩打包程序 unzip解压缩zip文件 rar打包压缩命令&unrar解压rar文件 tar打包工具 使用zip压缩文件 Linux中常见的压缩文件如下: 1.zip压缩打包程序 以下参数1表示压缩时间快体积大...

honzhang
2017/04/25
0
0
UBUNTU14.04下nautilus脚本解压含中文ZIP文件插件

一般用unzip命令解压含中文乱码的文件如下: unzip -O CP936 含中文文件名.zip 每次都这样做那太累,所以写了个小插件配合nautilus方便日常办公使用: 打开 ~/.local/share/nautilus/script...

91tel
2014/05/01
0
0
7z-linux下解决中文名乱码的终极办法

linux上安装7z主要是为了解决中文文件名乱码的问题,压缩率还是其次原因 具体安装看参考网址,建议用源码方式安装 官网下载地址:http://www.7-zip.org/download.html 源文件项目地址:http:...

爬墙
2016/03/12
391
0
使用ubuntu 10.04中的中文乱码问题解决

1、ibus输入法 Ubuntu 系统安装后已经自带了ibus输入法,在英语环境下默认不启动。 配置ibus自动启动可以在ubuntu系统菜单上选择System --- Preferences --- Startup Applications,在该窗口...

durban
2012/08/25
0
0
linux中显示中文乱码的问题

由于在windows下默认是gb编码,而我的vim默认是utf-8(gedit默认也是utf-8),所以打开会成乱码。修改了一下配置文件, 使vi 支持gb编码就好了。 $vi ~/.vimrc let &termencoding=&encoding...

zh119893
2014/05/13
1K
0
java批量下载乱码问题

系统有个打包批量下载excel报表数据的功能, 我是先用url下载方式去报表服务器下载,保存到web服务器上,文件名是报表的名称,含有中文, 然后多个excle打包成zip在下载给客户端,zip的文件名...

游荡在记忆深处
2015/11/12
195
3
让Tomcat支持中文路径名和中文文件名

让Tomcat支持中文路径名和中文文件名关键字: Tomcat 中文 中文文件名 下载 列出目录 Tomcat是Java开发者使用得较多的一个Web服务器,因为它占用资源小,运行速度快等特点,深受Java Web程序员...

enzozhong
2013/07/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Java基础——异常

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。 异常处理: 可以挖很多个陷阱,但是不要都是一样...

凯哥学堂
26分钟前
0
0
180723-Quick-Task 动态脚本支持框架之结构设计篇

文章链接:https://liuyueyi.github.io/hexblog/2018/07/23/180723-Quick-Task-动态脚本支持框架之结构设计篇/ Quick-Task 动态脚本支持框架之结构设计篇 相关博文: 180702-QuickTask动态脚本...

小灰灰Blog
29分钟前
0
0
SBT 常用开发技巧

SBT 一直以来都是 Scala 开发者不可言说的痛,最主要的原因就是官方文档维护质量较差,没有经过系统的、循序渐进式的整理,导致初学者入门门槛较高。虽然也有其它构建工具可以选择(例如 Mill...

joymufeng
33分钟前
0
0
HBase in Practice - 性能、监控及问题解决

李钰(社区ID:Yu Li),阿里巴巴计算平台事业部高级技术专家,HBase开源社区PMC&committer。开源技术爱好者,主要关注分布式系统设计、大数据基础平台建设等领域。连续4年基于HBase/HDFS设计和...

中国HBase技术社区
34分钟前
1
0
ES18-JAVA API 批量操作

1.批量查询 Multi Get API public static void multiGet() {// 批量查询MultiGetResponse response = getClient().prepareMultiGet().add("my_person", "my_index", "1")// 查......

贾峰uk
39分钟前
0
0
SpringBoot2.0使用health

1,引入actuator <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency> 2,application.properties ......

暗中观察
46分钟前
0
0
阿里巴巴Java开发规约

###编程规约 命名风格 【强制】代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束 【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。...

简心
51分钟前
0
0
如何用TypeScript来创建一个简单的Web应用

转载地址 如何用TypeScript来创建一个简单的Web应用 安装TypeScript 获取TypeScript工具的方式: 通过npm(Node.js包管理器) npm install -g typescript 构建你的第一个TypeScript文件 创建...

durban
55分钟前
0
0
分享好友,朋友圈自定义分享链接无效

这个问题是微信6.5.6版本以后,修改了分享规则:分享的连接必须在公众号后台设定的js安全域名内

LM_Mike
今天
0
0
2018年7月23日课程

一、LVS-DR介绍 director分配请求到不同的real server。real server 处理请求后直接回应给用户,这样director负载均衡器仅处理客户机与服务器的一半连接。负载均衡器仅处理一半的连接,避免了...

人在艹木中
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部