compress/lzw 包仅提供解码器(lzw.reader),不包含编码器(lzw.writer),专为解析 gif/tiff 中嵌入的 lzw 流设计;其 lzw.newreader 要求 order(lsb/msb)和 litwidth(如 gif 固定为 8)必须与原始编码严格一致,否则报 invalid code 或 eof。

compress/lzw 在 Go 中仅支持解码(Reader),不提供编码(Writer)——这是最常被误踩的坑。它专为读取 GIF、TIFF 等格式中嵌入的 LZW 数据设计,不是通用 LZW 压缩工具。
为什么 compress/lzw 没有 Writer?
Go 标准库将 compress/lzw 定位为“解析已有 LZW 流”的工具,而非通用压缩实现。它的 Reader 严格遵循 LZW 的原始算法变体(如 LSB-first 位序、固定字典初始化、CLEAR 和 STOP 码处理),但编码逻辑未被纳入标准库范围。
- 官方文档明确标注:
Package lzw implements the Lempel-Ziv-Welch compressed data format. It is intended for use with the GIF and TIFF image formats. - 所有已知的 Go 标准库 LZW 示例(如
image/gif解码)都只调用lzw.NewReader - 试图用
lzw.NewWriter会编译失败:该函数根本不存在
如何正确解码 LZW 数据(lzw.NewReader 关键参数)
使用 lzw.NewReader 时,order 和 litWidth 必须与原始编码器完全一致,否则立即出现 invalid code 或提前 EOF。
-
order:指定字节序,lzw.LSB(GIF 使用)或lzw.MSB(TIFF 使用),错一个 bit 就全乱 -
litWidth:原始符号表宽度(不含控制码),GIF 固定为8(即 0–255),TIFF 可能为8或9 - 输入数据必须是原始 LZW 字节流,不能带头部(如 GIF 的
0x80块大小前缀需先跳过)
<pre class="brush:php;toolbar:false;">data := []byte{0x80, 0x10, 0x00, 0x00, /* ... raw LZW bytes after skip */ }
r := lzw.NewReader(bytes.NewReader(data[1:]), lzw.LSB, 8)
decoded, _ := io.ReadAll(r) // 注意:可能 panic,需加 error 检查
想压缩?别用 compress/lzw
,改用 compress/zlib 或第三方库Go 没有内置 LZW 编码器。强行自己实现易出错(比如 CLEAR 码重置逻辑、码宽动态增长、输出位序对齐)。实际项目中应:
- 优先考虑
compress/zlib(DEFLATE)或compress/gzip:压缩率更好、标准、安全 - 若协议强制要求 LZW 输出(如某些旧工业设备),用已验证的第三方库,例如
github.com/andybalholm/lzw - 注意:第三方
lzw库通常不兼容标准库的Reader参数约定,litWidth含义可能不同
真正麻烦的从来不是调用哪个函数,而是确认你手上的数据到底用的是 LSB 还是 MSB、初始字典宽度是多少、有没有预置 CLEAR 码——这些信息往往藏在设备手册第 47 页的脚注里,而不是错误日志中。











