Go 语言标准库 —— compress/flate 包(DEFLATE 压缩/解压缩)
🔹 概述
compress/flate 包实现了 RFC 1951 定义的 DEFLATE 压缩格式。
主要功能:
- DEFLATE 格式压缩
- DEFLATE 格式解压缩
- 可调节压缩级别
- 流式处理
重要说明:
- DEFLATE 是 gzip 和 zlib 的底层压缩算法
- 提供从无压缩到最大压缩的多个级别
- 支持流式压缩和解压缩
- 性能优秀,广泛应用于各种场景
压缩级别:
NoCompression(0) - 不压缩,仅存储BestSpeed(1) - 最快压缩速度,压缩率最低BestCompression(9) - 最大压缩率,速度最慢DefaultCompression(-1) - 默认压缩级别(平衡)HuffmanOnly(-2) - 仅 Huffman 编码(Go 1.15+)ConstantCompression(-2) - 常量压缩(同 HuffmanOnly)
🔹 核心类型
DEFLATE 写入器(压缩)
flate.Writer struct
-
说明:
- 实现了 io.WriteCloser 接口
- 将写入的数据进行 DEFLATE 压缩
- 支持可调节的压缩级别
-
字段:
- 内部自动管理,无需手动操作
-
创建方式:
// 创建新的写入器 func NewWriter(w io.Writer, level int) (*Writer, error) -
常用方法详解
-
Write 方法
- 说明:写入并压缩数据
- 方法:
Write(p []byte) (n int, err error) - 注意:
- 数据会被缓冲并压缩
- 返回写入的字节数(压缩前)
- 示例:
writer, _ := flate.NewWriter(file, flate.DefaultCompression) defer writer.Close() writer.Write([]byte("hello world"))
-
Flush 方法
- 说明:刷新缓冲区,强制输出所有 pending 数据
- 方法:
Flush() error - 注意:
- 不会关闭写入器
- 适合流式传输场景
- 示例:
writer.Write(data) writer.Flush() // 强制输出
-
Close 方法
- 说明:关闭写入器,写入结束标记
- 方法:
Close() error - 注意:
- 必须先调用 Close 才能完成压缩
- 之后不能再写入
- 示例:
writer.Write(data) err := writer.Close() // 完成压缩
-
Reset 方法
- 说明:重置写入器,复用对象
- 方法:
Reset(w io.Writer) - 注意:
- 保持压缩级别不变
- 减少内存分配
- 示例:
writer.Reset(newFile) // 复用写入器
-
-
示例(完整)
package main import ( "bytes" "compress/flate" "fmt" "io" "os" ) func main() { // 原始数据 data := []byte("Hello, World! This is a test of DEFLATE compression.") // 创建缓冲区存储压缩数据 var compressed bytes.Buffer // 创建 flate 写入器(默认压缩级别) writer, err := flate.NewWriter(&compressed, flate.DefaultCompression) if err != nil { fmt.Println("创建写入器失败:", err) return } // 写入数据 _, err = writer.Write(data) if err != nil { fmt.Println("写入失败:", err) return } // 关闭写入器(必须) err = writer.Close() if err != nil { fmt.Println("关闭失败:", err) return } // 显示压缩效果 fmt.Printf("原始大小:%d 字节\n", len(data)) fmt.Printf("压缩大小:%d 字节\n", compressed.Len()) fmt.Printf("压缩率:%.2f%%\n", float64(compressed.Len())/float64(len(data))*100) }
DEFLATE 读取器(解压缩)
flate.Reader struct
-
说明:
- 实现了 io.ReadCloser 接口
- 从底层读取器读取压缩数据并解压缩
- 流式处理,不需要一次性加载全部数据
-
字段:
- 内部自动管理,无需手动操作
-
创建方式:
// 创建新的读取器 func NewReader(r io.Reader) io.ReadCloser -
常用方法详解
-
Read 方法
- 说明:读取并解压缩数据
- 方法:
Read(p []byte) (n int, err error) - 注意:
- 实现了 io.Reader 接口
- 自动处理解压缩
- 读到末尾返回 io.EOF
- 示例:
reader := flate.NewReader(file) defer reader.Close() data, err := io.ReadAll(reader)
-
Close 方法
- 说明:关闭读取器,释放资源
- 方法:
Close() error - 注意:
- 使用完后必须关闭
- 之后不能再读取
- 示例:
reader := flate.NewReader(file) defer reader.Close()
-
Reset 方法
- 说明:重置读取器,复用对象
- 方法:
Reset(r io.Reader) - 注意:
- 减少内存分配
- 提高性能
- 示例:
reader.Reset(newFile) // 复用读取器
-
-
示例(完整)
package main import ( "bytes" "compress/flate" "fmt" "io" ) func main() { // 假设已有压缩数据 compressedData := []byte{ /* ... 压缩数据 ... */ } // 创建 flate 读取器 reader := flate.NewReader(bytes.NewReader(compressedData)) defer reader.Close() // 读取并解压缩 data, err := io.ReadAll(reader) if err != nil { fmt.Println("解压失败:", err) return } fmt.Printf("解压后大小:%d 字节\n", len(data)) fmt.Printf("内容:%s\n", string(data)) }
🔹 压缩级别常量
压缩级别定义
const (
NoCompression = 0 // 不压缩
BestSpeed = 1 // 最快压缩
BestCompression = 9 // 最大压缩
DefaultCompression = -1 // 默认压缩
ConstantCompression = -2 // 常量压缩(Huffman only)
HuffmanOnly = -2 // 仅 Huffman 编码
)
各压缩级别详解
-
NoCompression (0)
- 说明:不压缩,仅存储
- 速度:最快
- 压缩率:无压缩
- 使用场景:
- 数据已经是压缩格式
- 需要极快的处理速度
- 调试和测试
- 示例:
writer, _ := flate.NewWriter(dst, flate.NoCompression)
-
BestSpeed (1)
- 说明:最快的压缩速度
- 速度:非常快
- 压缩率:较低(约 20-30%)
- 使用场景:
- 实时传输
- 网络流媒体
- 对延迟敏感的应用
- 示例:
writer, _ := flate.NewWriter(dst, flate.BestSpeed)
-
DefaultCompression (-1)
- 说明:默认压缩级别(平衡)
- 速度:中等
- 压缩率:中等(约 40-60%)
- 使用场景:
- 一般用途
- 文件压缩
- 推荐首选
- 示例:
writer, _ := flate.NewWriter(dst, flate.DefaultCompression)
-
BestCompression (9)
- 说明:最大的压缩率
- 速度:最慢
- 压缩率:最高(约 60-80%)
- 使用场景:
- 归档存储
- 网络带宽有限
- 存储空间宝贵
- 示例:
writer, _ := flate.NewWriter(dst, flate.BestCompression)
-
HuffmanOnly (-2)
- 说明:仅使用 Huffman 编码
- 速度:快
- 压缩率:较低
- 使用场景:
- 需要快速压缩
- 数据已经有一定压缩
- 示例:
writer, _ := flate.NewWriter(dst, flate.HuffmanOnly)
压缩级别对比示例
package main
import (
"bytes"
"compress/flate"
"fmt"
"io"
"strings"
)
func compressLevel(data []byte, level int) ([]byte, float64) {
var buf bytes.Buffer
writer, _ := flate.NewWriter(&buf, level)
writer.Write(data)
writer.Close()
ratio := float64(buf.Len()) / float64(len(data)) * 100
return buf.Bytes(), ratio
}
func main() {
// 生成测试数据(重复文本压缩率更高)
data := []byte(strings.Repeat("Hello, World! This is a test of DEFLATE compression. ", 100))
levels := []struct {
name string
level int
}{
{"NoCompression", flate.NoCompression},
{"BestSpeed", flate.BestSpeed},
{"DefaultCompression", flate.DefaultCompression},
{"BestCompression", flate.BestCompression},
{"HuffmanOnly", flate.HuffmanOnly},
}
fmt.Printf("原始大小:%d 字节\n\n", len(data))
fmt.Println("压缩级别对比:")
fmt.Println("------------------------")
for _, l := range levels {
compressed, ratio := compressLevel(data, l.level)
fmt.Printf("%-20s: %6d 字节 (%.2f%%)\n", l.name, len(compressed), ratio)
}
}
🔹 使用场景
1. 基础压缩和解压缩
package main
import (
"bytes"
"compress/flate"
"fmt"
"io"
)
func main() {
// 原始数据
original := []byte("Hello, World! This is a test of DEFLATE compression algorithm.")
// 压缩
var compressed bytes.Buffer
writer, err := flate.NewWriter(&compressed, flate.DefaultCompression)
if err != nil {
fmt.Println("创建压缩器失败:", err)
return
}
writer.Write(original)
writer.Close()
// 解压缩
reader := flate.NewReader(&compressed)
decompressed, err := io.ReadAll(reader)
reader.Close()
if err != nil {
fmt.Println("解压失败:", err)
return
}
// 验证
fmt.Printf("原始大小:%d 字节\n", len(original))
fmt.Printf("压缩大小:%d 字节\n", compressed.Len())
fmt.Printf("解压大小:%d 字节\n", len(decompressed))
fmt.Printf("数据一致:%v\n", bytes.Equal(original, decompressed))
}
2. 文件压缩和解压缩
package main
import (
"compress/flate"
"fmt"
"io"
"os"
)
func compressFile(src, dst string, level int) error {
// 打开源文件
srcFile, err := os.Open(src)
if err != nil {
return fmt.Errorf("打开源文件:%w", err)
}
defer srcFile.Close()
// 创建目标文件
dstFile, err := os.Create(dst)
if err != nil {
return fmt.Errorf("创建目标文件:%w", err)
}
defer dstFile.Close()
// 创建 flate 写入器
writer, err := flate.NewWriter(dstFile, level)
if err != nil {
return fmt.Errorf("创建压缩器:%w", err)
}
// 复制并压缩
_, err = io.Copy(writer, srcFile)
if err != nil {
writer.Close()
return fmt.Errorf("压缩失败:%w", err)
}
err = writer.Close()
if err != nil {
return fmt.Errorf("关闭压缩器:%w", err)
}
// 显示压缩效果
srcInfo, _ := os.Stat(src)
dstInfo, _ := os.Stat(dst)
ratio := float64(dstInfo.Size()) / float64(srcInfo.Size()) * 100
fmt.Printf("压缩完成:%s -> %s\n", src, dst)
fmt.Printf("压缩率:%.2f%%\n", ratio)
return nil
}
func decompressFile(src, dst string) error {
// 打开源文件
srcFile, err := os.Open(src)
if err != nil {
return fmt.Errorf("打开源文件:%w", err)
}
defer srcFile.Close()
// 创建目标文件
dstFile, err := os.Create(dst)
if err != nil {
return fmt.Errorf("创建目标文件:%w", err)
}
defer dstFile.Close()
// 创建 flate 读取器
reader := flate.NewReader(srcFile)
defer reader.Close()
// 复制并解压
_, err = io.Copy(dstFile, reader)
if err != nil {
return fmt.Errorf("解压失败:%w", err)
}
fmt.Printf("解压完成:%s -> %s\n", src, dst)
return nil
}
func main() {
// 压缩
err := compressFile("input.txt", "input.txt.deflate", flate.DefaultCompression)
if err != nil {
fmt.Println("压缩失败:", err)
return
}
// 解压
err = decompressFile("input.txt.deflate", "output.txt")
if err != nil {
fmt.Println("解压失败:", err)
return
}
}
3. HTTP 响应压缩
package main
import (
"compress/flate"
"fmt"
"net/http"
"strings"
)
func compressedHandler(w http.ResponseWriter, r *http.Request) {
// 检查客户端是否支持 deflate
if !strings.Contains(r.Header.Get("Accept-Encoding"), "deflate") {
// 不支持压缩,返回普通内容
fmt.Fprintln(w, "Your client does not support deflate compression")
return
}
// 设置压缩头
w.Header().Set("Content-Encoding", "deflate")
w.Header().Set("Vary", "Accept-Encoding")
// 创建 flate 写入器
writer, err := flate.NewWriter(w, flate.DefaultCompression)
if err != nil {
http.Error(w, "Compression failed", http.StatusInternalServerError)
return
}
defer writer.Close()
// 写入响应内容
content := strings.Repeat("This is compressed content. ", 1000)
writer.Write([]byte(content))
writer.Flush() // 确保数据被发送
}
func main() {
http.HandleFunc("/", compressedHandler)
fmt.Println("Server starting on :8080")
http.ListenAndServe(":8080", nil)
}
4. 流式压缩(实时数据)
package main
import (
"compress/flate"
"fmt"
"io"
"os"
"time"
)
func main() {
// 创建管道
pr, pw := io.Pipe()
// 创建 flate 写入器
writer, err := flate.NewWriter(pw, flate.DefaultCompression)
if err != nil {
fmt.Println("创建压缩器失败:", err)
return
}
// 启动解压缩 goroutine
go func() {
reader := flate.NewReader(pr)
defer reader.Close()
buf := make([]byte, 1024)
for {
n, err := reader.Read(buf)
if err == io.EOF {
break
}
if err != nil {
fmt.Println("解压错误:", err)
break
}
// 处理解压后的数据
os.Stdout.Write(buf[:n])
}
}()
// 模拟实时数据生成
for i := 0; i < 10; i++ {
data := fmt.Sprintf("Line %d: Real-time data at %v\n", i, time.Now())
writer.Write([]byte(data))
writer.Flush() // 实时发送
time.Sleep(100 * time.Millisecond)
}
writer.Close()
pw.Close()
}
5. 压缩池(复用对象)
package main
import (
"bytes"
"compress/flate"
"fmt"
"io"
"sync"
)
// 压缩池
type CompressorPool struct {
writers sync.Pool
}
func NewCompressorPool(level int) *CompressorPool {
return &CompressorPool{
writers: sync.Pool{
New: func() interface{} {
w, _ := flate.NewWriter(nil, level)
return w
},
},
}
}
func (p *CompressorPool) Compress(data []byte) ([]byte, error) {
// 从池中获取写入器
writer := p.writers.Get().(*flate.Writer)
defer p.writers.Put(writer)
var buf bytes.Buffer
writer.Reset(&buf)
_, err := writer.Write(data)
if err != nil {
return nil, err
}
err = writer.Close()
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// 解压池
type DecompressorPool struct {
readers sync.Pool
}
func NewDecompressorPool() *DecompressorPool {
return &DecompressorPool{
readers: sync.Pool{
New: func() interface{} {
return flate.NewReader(nil)
},
},
}
}
func (p *DecompressorPool) Decompress(data []byte) ([]byte, error) {
// 从池中获取读取器
reader := p.readers.Get().(io.ReadCloser)
defer p.readers.Put(reader)
reader.(flate.Resetter).Reset(bytes.NewReader(data))
return io.ReadAll(reader)
}
func main() {
compPool := NewCompressorPool(flate.DefaultCompression)
decompPool := NewDecompressorPool()
// 压缩
data := []byte("Test data for compression pooling")
compressed, err := compPool.Compress(data)
if err != nil {
fmt.Println("压缩失败:", err)
return
}
// 解压
decompressed, err := decompPool.Decompress(compressed)
if err != nil {
fmt.Println("解压失败:", err)
return
}
fmt.Printf("原始:%d 字节,压缩:%d 字节\n", len(data), len(compressed))
fmt.Printf("数据一致:%v\n", bytes.Equal(data, decompressed))
}
6. 并发压缩大文件
package main
import (
"compress/flate"
"fmt"
"io"
"os"
"sync"
)
type chunk struct {
data []byte
index int
}
func compressConcurrent(src, dst string, numWorkers int) error {
// 读取源文件
srcData, err := os.ReadFile(src)
if err != nil {
return fmt.Errorf("读取文件:%w", err)
}
// 分割数据块
chunkSize := len(srcData) / numWorkers
chunks := make(chan chunk, numWorkers)
results := make(chan struct {
data []byte
index int
}, numWorkers)
var wg sync.WaitGroup
// 启动工作协程
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for c := range chunks {
var buf bytes.Buffer
writer, _ := flate.NewWriter(&buf, flate.DefaultCompression)
writer.Write(c.data)
writer.Close()
results <- struct {
data []byte
index int
}{buf.Bytes(), c.index}
}
}()
}
// 发送数据块
for i := 0; i < numWorkers; i++ {
start := i * chunkSize
end := start + chunkSize
if i == numWorkers-1 {
end = len(srcData)
}
chunks <- chunk{
data: srcData[start:end],
index: i,
}
}
close(chunks)
// 等待完成
go func() {
wg.Wait()
close(results)
}()
// 收集结果
orderedResults := make([][]byte, numWorkers)
for r := range results {
orderedResults[r.index] = r.data
}
// 写入目标文件
dstFile, err := os.Create(dst)
if err != nil {
return fmt.Errorf("创建文件:%w", err)
}
defer dstFile.Close()
for _, data := range orderedResults {
dstFile.Write(data)
}
fmt.Printf("并发压缩完成:%d 个工作协程\n", numWorkers)
return nil
}
func main() {
err := compressConcurrent("largefile.txt", "largefile.txt.deflate", 4)
if err != nil {
fmt.Println("错误:", err)
}
}
7. 压缩数据校验
package main
import (
"bytes"
"compress/flate"
"crypto/md5"
"fmt"
"io"
)
func compressAndVerify(data []byte) error {
// 计算原始数据的 MD5
originalHash := md5.Sum(data)
fmt.Printf("原始数据 MD5: %x\n", originalHash)
// 压缩
var compressed bytes.Buffer
writer, err := flate.NewWriter(&compressed, flate.DefaultCompression)
if err != nil {
return err
}
writer.Write(data)
writer.Close()
fmt.Printf("压缩后大小:%d 字节\n", compressed.Len())
// 解压
reader := flate.NewReader(&compressed)
decompressed, err := io.ReadAll(reader)
reader.Close()
if err != nil {
return fmt.Errorf("解压失败:%w", err)
}
// 计算解压数据的 MD5
decompressedHash := md5.Sum(decompressed)
fmt.Printf("解压数据 MD5: %x\n", decompressedHash)
// 验证
if !bytes.Equal(originalHash[:], decompressedHash[:]) {
return fmt.Errorf("数据校验失败")
}
if !bytes.Equal(data, decompressed) {
return fmt.Errorf("数据内容不一致")
}
fmt.Println("✓ 数据校验通过")
return nil
}
func main() {
data := []byte("Test data for compression and verification. " +
"This should remain unchanged after compression and decompression.")
err := compressAndVerify(data)
if err != nil {
fmt.Println("错误:", err)
}
}
🔹 错误处理
常见错误
-
无效的压缩数据
- 说明:尝试解压非 DEFLATE 格式的数据
- 处理方式:检查错误并验证数据格式
- 示例:
reader := flate.NewReader(file) data, err := io.ReadAll(reader) if err != nil { fmt.Println("无效的压缩数据:", err) }
-
写入器未关闭
- 说明:忘记调用 Close() 导致数据不完整
- 处理方式:始终使用 defer Close()
- 示例:
writer, _ := flate.NewWriter(dst, level) defer writer.Close() // 确保关闭
-
压缩级别无效
- 说明:使用了不支持的压缩级别
- 处理方式:检查级别范围(-2 到 9)
- 示例:
if level < -2 || level > 9 { level = flate.DefaultCompression } writer, err := flate.NewWriter(dst, level)
错误处理最佳实践
package main
import (
"compress/flate"
"fmt"
"io"
"os"
)
func safeCompress(src, dst string) (err error) {
// 打开源文件
srcFile, err := os.Open(src)
if err != nil {
return fmt.Errorf("打开源文件:%w", err)
}
defer srcFile.Close()
// 创建目标文件
dstFile, err := os.Create(dst)
if err != nil {
return fmt.Errorf("创建目标文件:%w", err)
}
defer func() {
dstFile.Close()
if err != nil {
// 出错时删除不完整的文件
os.Remove(dst)
}
}()
// 创建 flate 写入器
writer, err := flate.NewWriter(dstFile, flate.DefaultCompression)
if err != nil {
return fmt.Errorf("创建压缩器:%w", err)
}
defer writer.Close()
// 复制并压缩
_, err = io.Copy(writer, srcFile)
if err != nil {
return fmt.Errorf("压缩失败:%w", err)
}
// 显式关闭(defer 也会关闭)
err = writer.Close()
if err != nil {
return fmt.Errorf("关闭压缩器:%w", err)
}
fmt.Println("压缩成功")
return nil
}
func safeDecompress(src, dst string) (err error) {
// 打开源文件
srcFile, err := os.Open(src)
if err != nil {
return fmt.Errorf("打开源文件:%w", err)
}
defer srcFile.Close()
// 创建目标文件
dstFile, err := os.Create(dst)
if err != nil {
return fmt.Errorf("创建目标文件:%w", err)
}
defer func() {
dstFile.Close()
if err != nil {
os.Remove(dst)
}
}()
// 创建 flate 读取器
reader := flate.NewReader(srcFile)
defer reader.Close()
// 复制并解压
_, err = io.Copy(dstFile, reader)
if err != nil {
return fmt.Errorf("解压失败:%w", err)
}
fmt.Println("解压成功")
return nil
}
func main() {
err := safeCompress("input.txt", "input.txt.deflate")
if err != nil {
fmt.Println("压缩失败:", err)
os.Exit(1)
}
err = safeDecompress("input.txt.deflate", "output.txt")
if err != nil {
fmt.Println("解压失败:", err)
os.Exit(1)
}
}
🔹 性能优化
1. 选择合适的压缩级别
package main
import (
"bytes"
"compress/flate"
"fmt"
"math/rand"
"time"
)
func benchmark(data []byte, level int) (compressedSize int, duration time.Duration) {
var buf bytes.Buffer
writer, _ := flate.NewWriter(&buf, level)
start := time.Now()
writer.Write(data)
writer.Close()
duration = time.Since(start)
return buf.Len(), duration
}
func main() {
// 生成随机数据
rand.Seed(time.Now().UnixNano())
data := make([]byte, 1024*1024) // 1MB
rand.Read(data)
levels := []int{
flate.NoCompression,
flate.BestSpeed,
flate.DefaultCompression,
flate.BestCompression,
}
fmt.Println("压缩级别性能对比 (1MB 随机数据):")
fmt.Println("----------------------------------------")
for _, level := range levels {
size, duration := benchmark(data, level)
ratio := float64(size) / float64(len(data)) * 100
fmt.Printf("级别 %d: 压缩后 %7d 字节 (%5.2f%%), 耗时 %v\n",
level, size, ratio, duration)
}
}
2. 使用缓冲 I/O
package main
import (
"bufio"
"compress/flate"
"fmt"
"io"
"os"
)
func compressWithBuffering(src, dst string) error {
srcFile, err := os.Open(src)
if err != nil {
return err
}
defer srcFile.Close()
dstFile, err := os.Create(dst)
if err != nil {
return err
}
defer dstFile.Close()
// 使用缓冲读取
bufReader := bufio.NewReaderSize(srcFile, 32*1024)
// 使用缓冲写入
bufWriter := bufio.NewWriterSize(dstFile, 32*1024)
// 创建 flate 写入器
writer, err := flate.NewWriter(bufWriter, flate.DefaultCompression)
if err != nil {
return err
}
_, err = io.Copy(writer, bufReader)
if err != nil {
writer.Close()
return err
}
err = writer.Close()
if err != nil {
return err
}
err = bufWriter.Flush()
if err != nil {
return err
}
fmt.Println("缓冲压缩完成")
return nil
}
func main() {
err := compressWithBuffering("input.txt", "output.txt.deflate")
if err != nil {
fmt.Println("错误:", err)
}
}
3. 对象池复用
package main
import (
"bytes"
"compress/flate"
"sync"
)
var (
writerPool = sync.Pool{
New: func() interface{} {
w, _ := flate.NewWriter(nil, flate.DefaultCompression)
return w
},
}
readerPool = sync.Pool{
New: func() interface{} {
return flate.NewReader(nil)
},
}
)
func compress(data []byte) ([]byte, error) {
writer := writerPool.Get().(*flate.Writer)
defer writerPool.Put(writer)
var buf bytes.Buffer
writer.Reset(&buf)
_, err := writer.Write(data)
if err != nil {
return nil, err
}
err = writer.Close()
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func decompress(data []byte) ([]byte, error) {
reader := readerPool.Get().(io.ReadCloser)
defer readerPool.Put(reader)
reader.(flate.Resetter).Reset(bytes.NewReader(data))
return io.ReadAll(reader)
}
🔹 与其他压缩格式对比
DEFLATE vs Gzip vs Zlib
| 特性 | DEFLATE (flate) | Gzip | Zlib |
|---|---|---|---|
| 格式 | 原始压缩算法 | 带文件头的 DEFLATE | 带校验的 DEFLATE |
| 文件扩展名 | .deflate | .gz | .zlib |
| 头部信息 | 无 | 有(文件名、时间戳) | 有(校验和) |
| 尾部校验 | 无 | 有(CRC32) | 有(Adler-32) |
| Go 包 | compress/flate | compress/gzip | compress/zlib |
| 压缩算法 | DEFLATE | DEFLATE | DEFLATE |
| 适用场景 | 底层实现、自定义协议 | 文件压缩、HTTP | 网络传输 |
关系说明
DEFLATE (压缩算法)
├── Gzip (DEFLATE + 文件头 + CRC32 校验)
├── Zlib (DEFLATE + 校验和)
└── PNG (使用 DEFLATE 压缩图像数据)
选择建议
- DEFLATE 👉 需要自定义协议、底层实现
- Gzip 👉 文件压缩、HTTP 响应压缩
- Zlib 👉 需要校验的网络传输
🔹 实际应用示例
1. 自定义压缩协议
package main
import (
"compress/flate"
"encoding/binary"
"fmt"
"io"
)
// 简单的压缩协议:[长度 4 字节][压缩数据]
func writeCompressed(w io.Writer, data []byte) error {
// 压缩数据
var compressed bytes.Buffer
writer, _ := flate.NewWriter(&compressed, flate.DefaultCompression)
writer.Write(data)
writer.Close()
// 写入长度
err := binary.Write(w, binary.BigEndian, uint32(compressed.Len()))
if err != nil {
return err
}
// 写入压缩数据
_, err = w.Write(compressed.Bytes())
return err
}
func readCompressed(r io.Reader) ([]byte, error) {
// 读取长度
var size uint32
err := binary.Read(r, binary.BigEndian, &size)
if err != nil {
return nil, err
}
// 读取压缩数据
compressed := make([]byte, size)
_, err = io.ReadFull(r, compressed)
if err != nil {
return nil, err
}
// 解压
reader := flate.NewReader(bytes.NewReader(compressed))
defer reader.Close()
return io.ReadAll(reader)
}
2. 日志压缩存储
package main
import (
"compress/flate"
"fmt"
"io"
"os"
"time"
)
type CompressedLogger struct {
file *os.File
writer *flate.Writer
}
func NewCompressedLogger(filename string) (*CompressedLogger, error) {
file, err := os.Create(filename)
if err != nil {
return nil, err
}
writer, err := flate.NewWriter(file, flate.DefaultCompression)
if err != nil {
file.Close()
return nil, err
}
return &CompressedLogger{
file: file,
writer: writer,
}, nil
}
func (cl *CompressedLogger) Write(entry string) error {
_, err := cl.writer.Write([]byte(entry + "\n"))
if err != nil {
return err
}
return cl.writer.Flush()
}
func (cl *CompressedLogger) Close() error {
err := cl.writer.Close()
if err != nil {
return err
}
return cl.file.Close()
}
func ReadCompressedLogger(filename string) ([]string, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
reader := flate.NewReader(file)
defer reader.Close()
data, err := io.ReadAll(reader)
if err != nil {
return nil, err
}
// 按行分割
lines := strings.Split(strings.TrimSpace(string(data)), "\n")
return lines, nil
}
func main() {
// 写入日志
logger, _ := NewCompressedLogger("app.log.deflate")
defer logger.Close()
for i := 0; i < 1000; i++ {
entry := fmt.Sprintf("[%s] INFO: Log entry %d", time.Now(), i)
logger.Write(entry)
}
// 读取日志
entries, _ := ReadCompressedLogger("app.log.deflate")
fmt.Printf("读取到 %d 条日志\n", len(entries))
}
🔹 注意事项和最佳实践
1. 必须关闭写入器
- ⚠️ 重要:忘记调用 Close() 会导致数据不完整
- ✅ 始终使用 defer Close()
- 示例:
writer, _ := flate.NewWriter(dst, level) defer writer.Close()
2. 选择合适的压缩级别
- ✅ 默认使用 DefaultCompression
- ✅ 需要速度用 BestSpeed
- ✅ 需要压缩率用 BestCompression
- ⚠️ BestCompression 可能慢 10 倍以上
3. 错误处理
- ✅ 检查所有错误
- ✅ 使用 defer 确保资源释放
- ✅ 失败时清理不完整的文件
4. 性能优化
- ✅ 使用对象池复用 Writer/Reader
- ✅ 大文件使用缓冲 I/O
- ✅ 考虑并发压缩
5. 数据完整性
- ✅ 解压后验证数据
- ✅ 使用校验和(如 MD5、CRC32)
- ✅ 处理损坏的压缩数据
🔥 总结
核心类型
- flate.Writer 👉 DEFLATE 压缩写入器(实现了 io.WriteCloser)
- flate.Reader 👉 DEFLATE 解压缩读取器(实现了 io.ReadCloser)
核心函数
- flate.NewWriter(w io.Writer, level int) 👉 创建压缩写入器
- flate.NewReader(r io.Reader) 👉 创建解压读取器
压缩级别
| 级别 | 值 | 说明 | 使用场景 |
|---|---|---|---|
| NoCompression | 0 | 不压缩 | 已压缩数据 |
| BestSpeed | 1 | 最快压缩 | 实时传输 |
| DefaultCompression | -1 | 默认(平衡) | 一般用途 |
| BestCompression | 9 | 最大压缩 | 归档存储 |
| HuffmanOnly | -2 | 仅 Huffman | 快速压缩 |
主要特点
- 标准算法 👉 RFC 1951 DEFLATE 标准实现
- 可调节级别 👉 从 0 到 9 多个压缩级别
- 流式处理 👉 支持实时数据流
- 广泛应用 👉 gzip、zlib、PNG 的基础
使用场景
- 文件压缩 👉 压缩大文件节省空间
- HTTP 压缩 👉 减少网络传输
- 自定义协议 👉 底层压缩需求
- 日志存储 👉 压缩历史日志
- 数据传输 👉 减少带宽使用
与其他包配合
- compress/gzip 👉 基于 flate 的文件压缩格式
- compress/zlib 👉 基于 flate 的网络传输格式
- bufio 👉 提高 I/O 性能
- io 👉 Copy、ReadAll 等操作
最佳实践
- ✅ 始终调用 Close() 完成压缩
- ✅ 使用 defer 确保资源释放
- ✅ 选择合适的压缩级别
- ✅ 使用对象池提高性能
- ✅ 完善的错误处理
- ✅ 验证解压数据完整性
- ⚠️ 注意:压缩级别越高不一定越好
性能提示
- 速度优先 👉 BestSpeed 或 NoCompression
- 空间优先 👉 BestCompression
- 平衡 👉 DefaultCompression(推荐)
- 大文件 👉 使用缓冲和并发
- 多次压缩 👉 使用对象池复用
compress/flate 包提供了强大的 DEFLATE 压缩功能,是 gzip 和 zlib 的基础,适合各种压缩需求!