compress/gzip 适合单流数据压缩(如日志、配置),需调用 gzip.Writer.Close() 否则解压报 invalid header;archive/zip 用于多文件归档,二者覆盖全部需求,无需第三方库。

archive/zip 和 compress/gzip 是 Go 标准库中唯二需要的包,不需要“框架库”——引入第三方 zip 库反而容易放大路径安全、中文名、空目录等基础问题。
压缩单文件用 compress/gzip 最简单
适合日志、配置、API 响应体等单流数据,不是打包归档。
-
gzip.Writer必须调用Close(),否则解压时会报invalid header - 小数据(bytes.Buffer;大文件务必流式处理,用
io.CopyBuffer配合 64KB 缓冲区 - 写入磁盘前,建议套一层
bufio.Writer,避免 syscall 频繁触发 - 别传整数给
SetLevel(),用gzip.BestSpeed或gzip.DefaultCompression
示例关键行:
gz := gzip.NewWriter(outputFile) gz.SetLevel(gzip.DefaultCompression) _, err = io.CopyBuffer(gz, inputFile, make([]byte, 64*1024)) gz.Close() // 这行不能少
打包多个文件必须用 archive/zip
不是“加个 loop 就行”,路径构造错会导致 ZIP 文件在 Windows/macOS 上静默失败或解压出错。
-
header.Name必须是相对路径,且开头不能有/或../;用filepath.Rel(basePath, fullPath)获取,再filepath.Clean()过滤逃逸 - 目录必须显式创建:
header.Name += "/"且header.Method = 0(不压缩),否则解压端无法识别为空目录 - Go 1.22+ 中文名需调
header.SetUTF8(true),否则 Linux 下正常、Windows 解压乱码 - 不要用
zip.FileInfoHeader(info)直接设名——它默认用info.Name(),对目录不带斜杠,也不处理路径
解压 ZIP 时最常踩的路径遍历坑
用户上传的 ZIP 若含 ../../../etc/passwd 这类路径,不校验会直接写到系统关键位置。
立即学习“go语言免费学习笔记(深入)”;
- 每个
file.Name必须过filepath.Clean(),再检查是否以".."开头或含"\0" - 用
filepath.Join(destDir, cleanName)拼目标路径,而不是字符串拼接 - 创建文件前,先
os.Stat()检查目标是否落在destDir内部(可用strings.HasPrefix(filepath.Abs(cleanPath), filepath.Abs(destDir))) - 遇到
file.IsDir()为 true 的条目,只os.MkdirAll(),不file.Open()


















