archive/zip 创建 zip 文件时需手动设置时间戳、处理路径安全、显式关闭资源、正确配置编码标志,否则会导致时间错误、文件泄漏、乱码或安全漏洞。

用 archive/zip 创建 zip 文件时,别漏掉 zip.FileHeader.SetModTime
默认情况下,zip.FileHeader 的修改时间是 Unix 零时刻(1970-01-01),解压后文件时间戳全错,某些构建工具或校验逻辑会因此失败。
- 手动调用
header.SetModTime(time.Now()),否则所有文件时间戳都一样且不合理 - 写入文件内容前必须先调用
zipWriter.CreateHeader(header),不能直接Write - 如果要压缩目录,得自己递归遍历路径,
archive/zip不提供“打包整个文件夹”这种便利函数 - 注意
os.Open打开源文件后记得Close,但zip.Writer.Close()会自动 flush 并关闭底层io.Writer,不用额外关
解压 zip 时,zip.Reader.Open 返回的 io.ReadCloser 必须显式 Close
不 Close 就会泄漏文件描述符,尤其在循环处理多个 zip 包时,很快触发 “too many open files” 错误 —— 这是最常被忽略的资源泄漏点。
-
rc, err := file.Open()后,必须配对defer rc.Close()或及时调用 - 不要用
ioutil.ReadAll(rc)后就以为完事了,rc还活着 - 解压到磁盘时,目标路径需提前
os.MkdirAll(filepath.Dir(dstPath), 0755),archive/zip不自动建父目录 - 文件名含
../是安全隐患,生产环境务必校验strings.HasPrefix(file.Name, "../") || strings.Contains(file.Name, "/../")
zip.FileHeader.Flags 影响中文文件名是否乱码,Windows 和 macOS 行为不一致
Windows 默认用 GBK/CP936 解码文件名,macOS/Linux 用 UTF-8;Go 的 archive/zip 默认按 UTF-8 写入,但没设标志位,导致 Windows 资源管理器打开显示乱码。
- 要兼容 Windows,请在创建
zip.FileHeader后设置:header.Flags = 1(表示文件名用 UTF-8 编码) - 注意:设了
Flags = 1后,旧版 Windows(如 Win7 自带解压)可能无法识别,需用 7-Zip 或新版系统 - 如果必须支持老旧环境,就得用
golang.org/x/text/encoding转成 GBK,再清空Flags,但此时 Linux/macOS 解压会乱码 —— 没有银弹,得按目标用户选
大文件压缩/解压卡住?别直接 io.Copy 整个 zip.File
直接 io.Copy(dst, zipFile) 看似简洁,但 zip 文件里可能有几十 MB 的单个文件,io.Copy 会一次性读进内存,OOM 风险高;更糟的是,它跳过了 header 校验,损坏 zip 也能“成功”解出垃圾数据。
立即学习“go语言免费学习笔记(深入)”;
- 正确做法:用
file.Open()得到io.ReadCloser,再用io.CopyBuffer(dst, src, make([]byte, 32*1024))控制缓冲区大小 - 压缩时也别
os.ReadFile整个文件再Write,应os.Open+io.Copy流式写入 - 解压前可用
file.FileInfo().Size()做粗略校验,比如限制单文件 > 100MB 就拒绝










