Go标准库默认仅归档不压缩,必须显式设header.Method=zip.Deflate才能启用Deflate压缩;中文名需Flags=1或SetUTF8(true),目录打包须用filepath.Rel+ToSlash转相对路径,解压须校验路径防Zip Slip。

Go 标准库能直接完成文件归档,但“归档”和“压缩”是两件事,不手动设压缩方式就只是打包、不减体积。
zip.Writer 默认不压缩,必须显式设 header.Method = zip.Deflate
你生成的 files.zip 体积和源文件加起来一样大?不是写错了,是 Go 默认用 zip.Store —— 纯拷贝、零压缩。调 w.Create() 或 w.CreateHeader() 都不会自动启用压缩。
- 每个文件写入前,必须拿到对应的
*zip.FileHeader,然后设header.Method = zip.Deflate - 空文件或已压缩格式(如
.jpg、.png)可能被底层 zlib 自动回退为Store,这是正常行为 - 文本类文件(
.go、.json、.log)才真正受益于Deflate
递归压缩目录时,路径必须归一化为 Unix 风格
用 filepath.WalkDir 遍历目录时,Windows 下 filepath.Rel() 返回带 \ 的路径,而 ZIP 规范只认 /。不处理会导致解压失败或路径错乱。
- 用
filepath.ToSlash(filepath.Clean(relPath))替换所有分隔符并清理./.. - 目录项的
Name必须以/结尾,且header.Mode().IsDir()为true - 空目录不会被
WalkDir回调到,需额外检测并手动调用w.CreateHeader(&zip.FileHeader{...})
解压 ZIP 必须校验路径,否则存在 Zip Slip 漏洞
archive/zip 完全不拦截 ../ 路径。传入 ../../../etc/passwd,它就真往系统目录写——Windows 资源管理器和 unzip -t 都不拦。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
立即学习“go语言免费学习笔记(深入)”;
- 对每个
f.Name先调filepath.Clean(),再检查是否含".."或以"."开头 - 构造目标路径:
absDst := filepath.Join(dstDir, cleanedName) - 用
strings.HasPrefix(filepath.ToSlash(absDst), filepath.ToSlash(expectedBase))确保没逃出目标根目录 - 遇到
f.IsDir() == true,必须调os.MkdirAll(filePath, 0755),ZIP 不保证父目录先出现
gzip 和 zip 职责分明,别混用
compress/gzip 只压缩单个流,不能打包;archive/zip 可打包多文件,但默认不压缩。想实现 tar.gz 效果,得嵌套使用:
- 先用
archive/tar写入 tar 流 → 套一层compress/gzip→ 最终写入文件 -
tar.Writer.Close()必须在gzip.Writer.Close()之前,否则gunzip -t报unexpected end of file -
gzip.Writer不调Close()就结束,输出文件为空或损坏(CRC 和 ISIZE 没写入)
最易被忽略的是:w.Close() 在 ZIP 打包中不可省略,gz.Close() 在 gzip 压缩中也不可省略——两者都负责写入尾部元数据,漏掉就等于生成了半成品文件。

















