go zip.writer默认用zip.store无压缩,需显式设header.method=zip.deflate;中文名要header.flags=1或setutf8(true);目录打包须用filepath.rel+toslash转相对路径。

Go 生成的 ZIP 文件体积没变小?不是代码写错了,是 zip.Writer 默认用 zip.Store——纯归档、零压缩。
为什么 zip.Writer.CreateHeader 后文件体积不变
因为 zip.Writer 对每个 zip.FileHeader 都默认走 zip.Store,哪怕你调了 CreateHeader 也不自动切到压缩模式。必须为每个文件头显式设置 header.Method = zip.Deflate 才启用 DEFLATE 压缩。
-
zip.Deflate是 Go 标准库唯一支持的压缩方法,zip.BestCompression等常量不存在 - 空文件或极小文件(如 Deflate,底层 zlib 也可能自动回退到
Store,这不是 bug - 已压缩格式(
.jpg、.png、.mp4)再压基本无效,甚至略增体积;文本类(.go、.json)才真正受益
中文文件名在 Windows 上乱码怎么办
Go 默认按 UTF-8 写文件名,但 Windows 资源管理器默认用 GBK 解码——两边不匹配,名字就变成 ???.txt。关键开关是 header.Flags = 1,表示文件名是 UTF-8 编码。
- Go 1.22+ 可用
header.SetUTF8(true)替代,更语义化 - 别试图用
golang.org/x/text/encoding/simplifiedchinese转 GBK:Windows 能认,Linux/macOS 解压就乱码 - 记得顺手设
header.SetModTime(time.Now()),否则所有文件时间戳一样,看着就很假
如何安全地打包目录(含子目录和空目录)
直接用 filepath.Abs() 拼路径会出问题:/home/user/a.txt 这种绝对路径传给 CreateHeader 可能被拒绝,或导致解压工具静默失败。
- 必须用
filepath.Rel(root, fullPath)获取相对路径,再用filepath.ToSlash()统一斜杠方向 - 对目录项,要显式设
header.Name += "/"并确保header.Mode().IsDir() == true,否则解压端可能无法识别为空目录 - 跳过
os.ModeDevice或os.ModeNamedPipe类型的条目,避免写入特殊设备文件
大文件压缩时内存暴涨或卡死
常见误用是把整个文件读进 []byte 再丢给 io.Copy,几百 MB 就吃光内存。archive/zip 本身支持流式处理,问题出在用法上。
- 压缩时:用
f, _ := os.Open(srcPath); defer f.Close(),然后io.Copy(writer, f)直接流式写入 - 并行读取多个文件时,可启动多个 goroutine 分别打开文件并发送到通道,由单个
zip.Writer顺序写入——既提速又不破坏 ZIP 结构 - 千万别用
bytes.Buffer或io.ReadAll缓存原始文件内容
最容易被忽略的其实是三件事:压缩前每个 header.Method = zip.Deflate 必须手动设、中文名必须开 Flags = 1、目录路径必须用 filepath.Rel + filepath.ToSlash 标准化。漏掉任意一个,ZIP 包就可能“看起来正常,用起来诡异”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











