github.com/golang/snappy 不提供 NewWriter 是因其为纯批量压缩包,仅暴露 Encode/Decode 函数;必须先 snappy.Encode 得到 []byte,再用 dst[:len(dst)] 截取真实长度写入文件,避免垃圾字节。

github.com/golang/snappy 不提供文件级接口,必须手动组合 os.File 和 snappy.Encode;直接用 snappy.Encode 压缩后再写入,比封装成 io.Writer 更可控、更少出错。
为什么不能像 gzip 那样用 snappy.NewWriter
Go 标准库的 compress/gzip 有 gzip.NewWriter,因为它是流式设计;但 github.com/golang/snappy 是纯批量(batch)压缩包,只暴露 Encode 和 Decode 两个函数,不实现 io.Writer。试图自己包装一个“snappy.Writer”容易漏掉长度校验、缓冲复用或 panic 边界,得不偿失。
压缩后写入文件的正确步骤
核心是:先压缩得到 []byte,再一次性写入文件。关键点不是“怎么写”,而是“怎么确保压缩结果干净可用”:
-
snappy.Encode(nil, src)返回新切片,len(dst)才是真实压缩长度,cap(dst)可能更大——必须用dst[:len(dst)]截取,否则文件里会混入零值垃圾字节 - 如果反复压缩小数据(如日志行),建议复用输出缓冲:
buf := make([]byte, 0, 4096),然后调snappy.Encode(buf[:0], src),避免高频 GC - Snappy 对极短输入("a" 压缩后变成 7 字节;若业务有大量超短 payload,应加长度判断,跳过压缩
完整可运行示例(含错误处理)
package main
import (
"os"
"github.com/golang/snappy"
)
func main() {
src := []byte("hello world! this is a test for snappy compression.")
// 压缩
compressed := snappy.Encode(nil, src)
// ✅ 必须截取有效长度
data := compressed[:len(compressed)]
// 写入文件
err := os.WriteFile("out.snappy", data, 0644)
if err != nil {
panic(err)
}
}
解压时最容易 panic 的地方
写入文件只是半程;读取后解压若直接 snappy.Decode(dst, src),而 dst 容量不够,就会 panic 报 snappy: corrupt input——这其实是越界写,错误信息极具误导性。安全做法永远是:
- 先调
snappy.DecodedLen(src)获取理论最大解压长度 - 按该长度分配
dst := make([]byte, snappy.DecodedLen(src)) - 再传给
snappy.Decode(dst, src),返回的decoded是dst[:n]形式,长度准确
Snappy 没有“自动扩容 dst”的机制,这点和 json.Unmarshal 或 proto.Unmarshal 完全不同,必须手算容量。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











