gzip.writer.close() 必须显式调用,否则因缓冲未刷新且crc/isize未写入导致压缩数据损坏;正确做法是写完立即调用w.close()并检查错误,大字符串需流式分块压缩避免oom。

gzip.Writer.Close() 必须显式调用,否则压缩数据损坏
不调用 Close() 是大字符串压缩后无法解压的头号原因。现象包括:gunzip -t file.gz 报 unexpected end of file,Python 的 gzip.open() 读取失败,或 Go 解压时出现 gzip: invalid checksum。
根本原因是 gzip.Writer 内部缓冲未刷新,且 GZIP 格式尾部的 CRC 和 ISIZE 字段只在 Close() 时写入。哪怕你用 io.Copy 写完全部内容,也不代表流已完整。
- 正确做法:写完后立刻调用
w.Close();defer w.Close()只有在所有写操作完成后才安全,若中间 panic 或提前 return,可能漏掉 - 错误写法:
io.Copy(w, bytes.NewReader(data)); return—— 没 Close,数据一定不完整 - 压缩失败(如磁盘满、权限不足)时,
w.Close()会返回 error,必须检查,不能忽略
内存中压缩大字符串必须避免 bytes.Buffer 累积全量数据
对几百 MB 甚至 GB 级字符串直接用 bytes.Buffer + gzip.Writer,极易触发 OOM。这不是压缩算法问题,而是 bytes.Buffer 无节制扩容导致的内存爆炸。
真正可行的路径是「流式分块」:把大字符串切片成固定大小块(如 1MB),每块单独压缩并发送/暂存,而不是等全部压缩完再取 buf.Bytes()。
- 若必须暂存压缩块(例如分片上传),每次
w.Write()后手动调用buf.Reset(),并在该块压缩完毕后立即w.Close() -
gzip.Writer默认缓冲区约 4KB,对大块写入效率低;可配合io.CopyBuffer(dst, src, make([]byte, 1 使用 1MB buffer,减少系统调用次数 - 别复用来自
bufio.Reader的底层[]byte切片——它会被后续读取覆盖;每次写入前必须copy()出独立副本
解压时别直接读 *os.File,必须用 gzip.NewReader 包裹
常见错误是打开 .gz 文件后,直接用 io.ReadAll(f) 或 bufio.Scanner 读取,结果得到的是乱码二进制流,而非原始字符串。
gzip.NewReader 不是装饰器,它是专用于解析 GZIP 流的 reader:跳过 magic header、校验 DEFLATE 块、处理校验和。绕过它,等于把压缩格式当裸字节处理。
- 解压必须链式构造:
gr, err := gzip.NewReader(f),然后io.ReadAll(gr)或io.Copy(dst, gr) -
gr.Close()必须调用,它释放内部资源(比如底层 reader 的状态),不关可能导致文件句柄泄漏或下次读取异常 - 别依赖
gr.Close()判断数据是否读完——它只释放资源;数据边界由io.EOF标识,io.Copy内部已正确处理,比手写循环更可靠 - 若需逐块控制(如限速、进度上报),每次
gr.Read(p)后必须同时检查n和err:仅当n == 0 && err == io.EOF或err != nil && err != io.EOF才退出
HTTP 场景选 compress/gzip,自定义协议优先 compress/zlib
传输场景下,压缩格式必须与接收方解压能力严格匹配。不是“哪个压缩率高就用哪个”,而是“对方能认出哪个”。
compress/gzip 输出带标准 magic header(1f 8b),HTTP 客户端自动识别 Content-Encoding: gzip 并解压;compress/zlib 输出无 magic header,HTTP 服务端(如 nginx)或浏览器会直接拒收。
- HTTP API 响应/请求体:一律用
compress/gzip,客户端(curl、fetch、axios)开箱即用 - TCP 自定义协议、RPC 二进制帧、嵌入式设备通信:优先
compress/zlib,体积更小(少 18 字节 header),且zlib.NewReader支持zlib.NoHeader模式跳过校验,降低开销 - 严禁混用:用
gzip.NewWriter压缩的数据,zlib.NewReader会报zlib: invalid header;反之亦然
Close()、每一次 copy()、每一层 NewReader 的包裹,都是实际线上踩坑后凝结的刚性约束。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











