gzip.writer.close()必须调用,否则生成的.gz文件因缺失crc32校验值和isize字段而解压失败;flush()无效,close()是唯一写入尾部元数据的操作。

gzip.Writer.Close() 必须调用,否则生成的 .gz 文件大概率解压失败——不是“可能出错”,而是 GZIP 格式规范强制要求的尾部字段(CRC32 校验值和原始长度 ISIZE)只在 Close() 时写入。
为什么文件压缩后解不开或报 unexpected EOF
90% 的原因是漏掉了 gz.Close()。现象包括:gunzip -t file.gz 报 unexpected end of file;Python 的 gzip.open() panic;zcat 提示 invalid compressed data。
Flush() 完全无效:它只刷新已压缩的数据块,不写尾部元数据,标准解压器直接拒收。
- 必须在
io.Copy(gz, src)或gz.Write()之后显式调用gz.Close() -
defer gz.Close()是安全写法,但要确保它出现在所有return之前(比如if err != nil { return err }后面没 defer 就会跳过) -
gz.Close()返回error,不能忽略——磁盘满、权限不足等底层失败就在这里暴露
压缩单个文件 vs 多个文件:别混淆 archive 和 compress
compress/gzip 只处理「一个数据流」,输出的是单个 .gz 文件,不是打包工具。它不理解文件名、路径、目录结构。
- 想把
a.txt压成a.txt.gz→ 直接gzip.NewWriter(f)写入目标文件即可 - 想打包
a.txt + b.log→ 必须先用archive/tar构建 tar 流,再套gzip.NewWriter,最终生成archive.tar.gz - 反复对同一个
gzip.Writer调用Write()写多个文件内容 → 没文件头、无分隔符,解压后只剩一团乱码或报tar: Unrecognized archive format
怎么选压缩级别?别硬套默认值
gzip.NewWriter() 默认用 gzip.DefaultCompression(值为 6),但实际场景中得看需求:
-
gzip.NoCompression(0):不压缩,只加 header,适合已压缩数据(如 JPEG、PNG) -
gzip.BestSpeed(1):最快,压缩率低,适合高频小日志、实时接口响应 -
gzip.BestCompression(9):最慢,体积最小,适合离线归档、静态资源预压缩 - 级别超出
[0,9]会panic,不是返回error—— 显式用gzip.NewWriterLevel(f, level)更安全
读取 .gz 文件时 io.Copy 失败?你跳过了 gzip.NewReader
常见错误:用 os.Open("x.gz") 得到 *os.File,直接传给 io.Copy(dst, src) —— 这是在复制原始二进制流,不是解压后的内容。
- 正确路径:先
gzip.NewReader(srcFile),再io.Copy(dst, gr) -
gzip.NewReader只认完整 GZIP 格式(magic bytes0x1f 0x8b开头),不接受裸deflate数据 - 若服务端用的是
Content-Encoding: deflate,得换用flate.NewReader或zlib.NewReader - 推荐一律用
io.Copy(dst, gr)解压,它内部已正确处理io.EOF和边界中断
Close() 不是可选项,是 GZIP 格式合法性的分水岭;而 gzip.NewReader 不是“可选封装”,是解压动作的必要入口——这两处最容易被当成“写了就行”而忽略其不可替代性。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











