Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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)GzipZlib
格式原始压缩算法带文件头的 DEFLATE带校验的 DEFLATE
文件扩展名.deflate.gz.zlib
头部信息有(文件名、时间戳)有(校验和)
尾部校验有(CRC32)有(Adler-32)
Go 包compress/flatecompress/gzipcompress/zlib
压缩算法DEFLATEDEFLATEDEFLATE
适用场景底层实现、自定义协议文件压缩、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) 👉 创建解压读取器

压缩级别

级别说明使用场景
NoCompression0不压缩已压缩数据
BestSpeed1最快压缩实时传输
DefaultCompression-1默认(平衡)一般用途
BestCompression9最大压缩归档存储
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 的基础,适合各种压缩需求!