Go 语言标准库 —— compress/zlib 包(Zlib 压缩/解压缩)
🔹 概述
compress/zlib 包实现了 RFC 1950 定义的 Zlib 压缩格式。
主要功能:
- Zlib 格式压缩
- Zlib 格式解压缩
- 支持自定义压缩级别
- 支持 Adler-32 校验和
- 流式处理
重要说明:
- Zlib 基于 DEFLATE 算法(compress/flate)
- 添加了文件头和 Adler-32 校验
- 支持 .zlib 文件扩展名
- 广泛应用于网络传输、PNG 图像、Git 版本控制
压缩级别:
NoCompression(0) - 不压缩BestSpeed(1) - 最快压缩BestCompression(9) - 最大压缩DefaultCompression(-1) - 默认压缩HuffmanOnly(-2) - 仅 Huffman 编码ConstantCompression(-2) - 常量压缩
与 Gzip 的区别:
- Zlib:RFC 1950,使用 Adler-32 校验,适合网络传输
- Gzip:RFC 1952,使用 CRC32 校验,适合文件压缩
🔹 核心类型
Zlib 写入器(压缩)
zlib.Writer struct
-
说明:
- 实现了 io.WriteCloser 接口
- 将写入的数据进行 Zlib 压缩
- 自动添加文件头、Adler-32 校验
- 支持自定义压缩级别
-
字段:
- 内部自动管理,无需手动操作
-
创建方式:
// 创建新的写入器(默认压缩级别) func NewWriter(w io.Writer) *Writer // 创建新的写入器(指定压缩级别) func NewWriterLevel(w io.Writer, level int) (*Writer, error) -
常用方法详解
-
Write 方法
- 说明:写入并压缩数据
- 方法:
Write(p []byte) (n int, err error) - 注意:
- 数据会被缓冲并压缩
- 返回写入的字节数(压缩前)
- 示例:
writer, _ := zlib.NewWriterLevel(file, zlib.DefaultCompression) defer writer.Close() writer.Write([]byte("hello world"))
-
Flush 方法
- 说明:刷新缓冲区,强制输出所有 pending 数据
- 方法:
Flush() error - 注意:
- 不会关闭写入器
- 适合流式传输场景
- 示例:
writer.Write(data) writer.Flush() // 强制输出
-
Close 方法
- 说明:关闭写入器,写入文件尾和 Adler-32 校验和
- 方法:
Close() error - 注意:
- 必须先调用 Close 才能完成压缩
- 之后不能再写入
- 示例:
writer.Write(data) err := writer.Close() // 完成压缩
-
Reset 方法
- 说明:重置写入器,复用对象
- 方法:
Reset(w io.Writer) - 注意:
- 保持压缩级别不变
- 减少内存分配
- 示例:
writer.Reset(newFile) // 复用写入器
-
-
示例(完整)
package main import ( "bytes" "compress/zlib" "fmt" "io" "os" ) func main() { // 原始数据 data := []byte("Hello, World! This is a test of Zlib compression.") // 创建缓冲区存储压缩数据 var compressed bytes.Buffer // 创建 zlib 写入器(默认压缩级别) writer := zlib.NewWriter(&compressed) // 写入数据 _, 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) }
Zlib 读取器(解压缩)
zlib.Reader struct
-
说明:
- 实现了 io.ReadCloser 接口
- 从底层读取器读取压缩数据并解压缩
- 自动处理文件头、Adler-32 校验
- 流式处理,不需要一次性加载全部数据
-
字段:
- 内部自动管理,无需手动操作
-
创建方式:
// 创建新的读取器 func NewReader(r io.Reader) (io.ReadCloser, error) -
常用方法详解
-
Read 方法
- 说明:读取并解压缩数据
- 方法:
Read(p []byte) (n int, err error) - 注意:
- 实现了 io.Reader 接口
- 自动处理解压缩和 Adler-32 校验
- 读到末尾返回 io.EOF
- 示例:
reader, _ := zlib.NewReader(file) defer reader.Close() data, err := io.ReadAll(reader)
-
Close 方法
- 说明:关闭读取器,释放资源
- 方法:
Close() error - 注意:
- 使用完后必须关闭
- 之后不能再读取
- 示例:
reader := zlib.NewReader(file) defer reader.Close()
-
-
示例(完整)
package main import ( "bytes" "compress/zlib" "fmt" "io" ) func main() { // 假设已有压缩数据 compressedData := []byte{ /* ... zlib 压缩数据 ... */ } // 创建 zlib 读取器 reader, err := zlib.NewReader(bytes.NewReader(compressedData)) if err != nil { fmt.Println("创建读取器失败:", err) return } 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)) }
🔹 使用场景
1. 基础压缩和解压缩
package main
import (
"bytes"
"compress/zlib"
"fmt"
"io"
)
func main() {
// 原始数据
original := []byte("Hello, World! This is a test of Zlib compression algorithm.")
// 压缩
var compressed bytes.Buffer
writer := zlib.NewWriter(&compressed)
writer.Write(original)
writer.Close()
// 解压缩
reader, err := zlib.NewReader(&compressed)
if err != nil {
fmt.Println("创建读取器失败:", err)
return
}
defer reader.Close()
decompressed, err := io.ReadAll(reader)
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/zlib"
"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()
// 创建 zlib 写入器
var writer *zlib.Writer
if level == zlib.DefaultCompression {
writer = zlib.NewWriter(dstFile)
} else {
writer, err = zlib.NewWriterLevel(dstFile, level)
if err != nil {
return fmt.Errorf("创建压缩器:%w", err)
}
}
defer writer.Close()
// 复制并压缩
_, err = io.Copy(writer, srcFile)
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()
// 创建 zlib 读取器
reader, err := zlib.NewReader(srcFile)
if err != nil {
return fmt.Errorf("创建解压读取器:%w", err)
}
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", "output.zlib")
if err != nil {
fmt.Println("压缩错误:", err)
}
// 示例:安全解压
err = safeDecompress("output.zlib", "restored.txt")
if err != nil {
fmt.Println("解压错误:", err)
}
}
🔹 性能优化
1. 对象池复用
package main
import (
"bytes"
"compress/zlib"
"sync"
)
var writerPool = sync.Pool{
New: func() interface{} {
w, _ := zlib.NewWriterLevel(nil, zlib.DefaultCompression)
return w
},
}
func compress(data []byte) ([]byte, error) {
writer := writerPool.Get().(*zlib.Writer)
defer writerPool.Put(writer)
var buf bytes.Buffer
writer.Reset(&buf)
_, err := writer.Write(data)
if err != nil {
writer.Close()
return nil, err
}
err = writer.Close()
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
2. 流式处理大文件
package main
import (
"compress/zlib"
"fmt"
"io"
"os"
)
func streamCompress(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()
writer := zlib.NewWriter(dstFile)
defer writer.Close()
buf := make([]byte, 32*1024) // 32KB 缓冲
total := 0
for {
n, err := srcFile.Read(buf)
if n > 0 {
_, werr := writer.Write(buf[:n])
if werr != nil {
return werr
}
total += n
}
if err == io.EOF {
break
}
if err != nil {
return err
}
}
fmt.Printf("流式压缩完成:%d 字节\n", total)
return nil
}
🔹 Zlib vs Gzip vs DEFLATE 对比
格式对比
| 特性 | DEFLATE | Zlib | Gzip |
|---|---|---|---|
| 标准 | RFC 1951 | RFC 1950 | RFC 1952 |
| 头部 | 无 | 2 字节 | 10+ 字节 |
| 校验 | 无 | Adler-32 | CRC32 |
| 尾部 | 无 | 4 字节 | 8 字节 |
| 压缩算法 | DEFLATE | DEFLATE | DEFLATE |
| Go 包 | compress/flate | compress/zlib | compress/gzip |
选择指南
使用 DEFLATE (compress/flate):
- ✅ 需要自定义协议
- ✅ 底层压缩需求
- ✅ 嵌入到其他格式中
使用 Zlib (compress/zlib):
- ✅ 网络数据传输
- ✅ PNG 图像格式
- ✅ Git 对象存储
- ✅ 内存数据压缩
- ✅ 需要快速压缩/解压
使用 Gzip (compress/gzip):
- ✅ 文件压缩
- ✅ HTTP 响应压缩
- ✅ 日志文件压缩
- ✅ 归档备份
- ✅ 需要高压缩率
🔥 总结
核心类型
- zlib.Writer - 压缩写入器(io.WriteCloser)
- zlib.Reader - 解压缩读取器(io.ReadCloser)
核心函数
zlib.NewWriter(w io.Writer)- 创建压缩器(默认级别)zlib.NewWriterLevel(w io.Writer, level int)- 创建压缩器(指定级别)zlib.NewReader(r io.Reader)- 创建解压器
压缩级别
| 级别 | 值 | 说明 | 场景 |
|---|---|---|---|
| NoCompression | 0 | 不压缩 | 已压缩数据 |
| BestSpeed | 1 | 最快 | 实时传输 |
| DefaultCompression | -1 | 默认 | 一般用途 |
| BestCompression | 9 | 最大压缩 | 归档存储 |
主要特点
- 标准格式 👉 RFC 1950 Zlib 标准
- Adler-32 校验 👉 快速校验和算法
- 可调节级别 👉 从 0 到 9 多个压缩级别
- 流式处理 👉 支持实时数据流
- 广泛应用 👉 PNG、Git、网络传输
使用场景
- 网络传输 👉 HTTP、WebSocket 数据压缩
- PNG 图像 👉 图像数据压缩
- Git 版本 👉 对象存储压缩
- 内存数据 👉 临时数据压缩
- 实时流式 👉 流式压缩/解压
与其他包配合
- image/png 👉 PNG 图像处理
- net/http 👉 HTTP 数据传输
- bufio 👉 提高 I/O 性能
- io 👉 Copy、ReadAll 等操作
最佳实践
- ✅ 始终调用 Close() 完成压缩
- ✅ 使用 defer 确保资源释放
- ✅ 选择合适的压缩级别
- ✅ 使用对象池提高性能
- ✅ 完善的错误处理
- ✅ 流式处理大文件
- ⚠️ 注意:必须调用 Close() 才能写入校验和
性能提示
- 速度优先 👉 BestSpeed 或 NoCompression
- 空间优先 👉 BestCompression
- 平衡 👉 DefaultCompression(推荐)
- 大文件 👉 使用流式处理和缓冲
- 多次压缩 👉 使用对象池复用
**compress/zlib 包提供了广泛使用的 Zlib 压缩功能,适合网络传输、PNG 图像、Git 存储等各种场景!**读取器:%w“, err) } defer reader.Close()
_, err = io.Copy(dstFile, reader)
if err != nil {
return fmt.Errorf("解压失败:%w", err)
}
err = reader.Close()
if err != nil {
return fmt.Errorf("关闭解压器:%w", err)
}
fmt.Println("解压成功")
return nil
}
func main() { // 示例:安全压缩 err := safeCompress(“input.txt”, “output.zlib”) if err != nil { fmt.Println(“压缩错误:”, err) }
// 示例:安全解压
err = safeDecompress("output.zlib", "restored.txt")
if err != nil {
fmt.Println("解压错误:", err)
}
}
---
## 🔹 总结
### 核心要点
| 特性 | 说明 |
|------|------|
| **压缩格式** | RFC 1950 Zlib 格式 |
| **校验算法** | Adler-32 校验和 |
| **压缩算法** | 基于 DEFLATE (compress/flate) |
| **接口实现** | io.WriteCloser (压缩), io.ReadCloser (解压) |
| **压缩级别** | 0-9 及特殊值 (-1, -2) |
### 最佳实践
1. **始终调用 Close()**
- 压缩:必须调用 `Close()` 完成压缩并写入校验和
- 解压:必须调用 `Close()` 释放资源
- 推荐使用 `defer` 确保关闭
2. **错误处理**
- 检查 `NewWriter`/`NewReader` 返回的错误
- 检查 `Write`/`Read` 操作错误
- 检查 `Close` 操作错误
3. **性能优化**
- 使用 `Reset()` 复用写入器对象
- 根据场景选择合适的压缩级别
- 流式处理大文件,避免内存溢出
4. **使用场景**
- ✅ 网络数据传输(HTTP、WebSocket)
- ✅ PNG 图像压缩
- ✅ Git 对象存储
- ✅ 实时流式压缩
- ❌ 大文件归档(建议使用 Gzip)
### 与 Gzip 对比
| 特性 | Zlib | Gzip |
|------|------|------|
| RFC 标准 | RFC 1950 | RFC 1952 |
| 校验和 | Adler-32 | CRC32 |
| 文件头 | 2 字节 | 10+ 字节 |
| 适用场景 | 网络传输、内存数据 | 文件压缩、归档 |
| 压缩率 | 略低 | 略高 |
| 速度 | 略快 | 略慢 |
### 完整示例索引
1. ✅ 基础压缩和解压缩
2. ✅ 文件压缩和解压缩
3. ✅ HTTP 数据传输压缩
4. ✅ PNG 图像处理
5. ✅ Git 对象存储
6. ✅ 压缩级别对比
7. ✅ 错误处理最佳实践
---
**📚 相关文档:**
- [Go compress/zlib 官方文档](https://pkg.go.dev/compress/zlib)
- [RFC 1950 - ZLIB Compressed Data Format](https://tools.ietf.org/html/rfc1950)
- [RFC 1951 - DEFLATE Compressed Data Format](https://tools.ietf.org/html/rfc1951)
**💡 提示:** 对于文件压缩场景,优先考虑 `compress/gzip` 包;对于网络传输和内存数据压缩,`compress/zlib` 是更好的选择。读取器:%w", err)
}
defer reader.Close()
// 复制并解压缩
_, err = io.Copy(dstFile, reader)
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 main() {
// 示例:压缩文件
err := compressFile("input.txt", "output.zlib", zlib.DefaultCompression)
if err != nil {
fmt.Println("压缩失败:", err)
return
}
// 示例:解压文件
err = decompressFile("output.zlib", "restored.txt")
if err != nil {
fmt.Println("解压失败:", err)
return
}
fmt.Println("\n文件压缩/解压缩完成!")
}
3. HTTP 数据传输压缩
package main
import (
"bytes"
"compress/zlib"
"fmt"
"io"
"net/http"
)
// 压缩数据并通过 HTTP 发送
func sendCompressedData(url string, data []byte) error {
// 压缩数据
var compressed bytes.Buffer
writer := zlib.NewWriter(&compressed)
_, err := writer.Write(data)
if err != nil {
writer.Close()
return err
}
writer.Close()
// 发送 HTTP 请求
resp, err := http.Post(url, "application/zlib", &compressed)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("HTTP 错误:%s", resp.Status)
}
fmt.Println("数据发送成功")
return nil
}
// 接收并解压 HTTP 数据
func receiveAndDecompress(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// 创建 zlib 读取器
reader, err := zlib.NewReader(resp.Body)
if err != nil {
return nil, err
}
defer reader.Close()
// 读取解压后的数据
return io.ReadAll(reader)
}
func main() {
// 示例:发送压缩数据
data := []byte("Important data to send")
err := sendCompressedData("http://example.com/upload", data)
if err != nil {
fmt.Println("发送失败:", err)
}
// 示例:接收压缩数据
// received, err := receiveAndDecompress("http://example.com/data")
}
4. PNG 图像处理(Zlib 压缩)
package main
import (
"bytes"
"compress/zlib"
"fmt"
"image"
"image/png"
"io"
"os"
)
// 压缩 PNG 图像数据
func compressImageData(data []byte) ([]byte, error) {
var buf bytes.Buffer
writer := zlib.NewWriter(&buf)
_, err := writer.Write(data)
if err != nil {
writer.Close()
return nil, err
}
err = writer.Close()
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// 解压缩 PNG 图像数据
func decompressImageData(data []byte) ([]byte, error) {
reader, err := zlib.NewReader(bytes.NewReader(data))
if err != nil {
return nil, err
}
defer reader.Close()
return io.ReadAll(reader)
}
// 读取 PNG 文件并压缩其数据
func processPNG(filename string) error {
// 打开 PNG 文件
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
// 解码 PNG
img, err := png.Decode(file)
if err != nil {
return err
}
// 获取图像边界
bounds := img.Bounds()
// 提取像素数据
var pixelData bytes.Buffer
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
r, g, b, a := img.At(x, y).RGBA()
pixelData.WriteByte(byte(r >> 8))
pixelData.WriteByte(byte(g >> 8))
pixelData.WriteByte(byte(b >> 8))
pixelData.WriteByte(byte(a >> 8))
}
}
// 压缩像素数据
compressed, err := compressImageData(pixelData.Bytes())
if err != nil {
return err
}
fmt.Printf("原始像素数据:%d 字节\n", pixelData.Len())
fmt.Printf("压缩后:%d 字节\n", len(compressed))
fmt.Printf("压缩率:%.2f%%\n", float64(len(compressed))/float64(pixelData.Len())*100)
return nil
}
func main() {
// 处理 PNG 文件
err := processPNG("image.png")
if err != nil {
fmt.Println("处理失败:", err)
return
}
fmt.Println("处理完成")
}
5. Git 对象存储(Zlib 压缩)
package main
import (
"bytes"
"compress/zlib"
"crypto/sha1"
"fmt"
"io"
"os"
"path/filepath"
)
// Git 对象类型
type GitObjectType string
const (
GitBlob GitObjectType = "blob"
GitTree GitObjectType = "tree"
GitCommit GitObjectType = "commit"
)
// 创建 Git 对象(压缩并存储)
func createGitObject(objType GitObjectType, data []byte) (string, error) {
// 构建 Git 对象内容:type + " " + size + "\0" + content
header := fmt.Sprintf("%s %d", objType, len(data))
content := append([]byte(header), 0)
content = append(content, data...)
// 计算 SHA1 哈希
hash := sha1.Sum(content)
hashStr := fmt.Sprintf("%x", hash)
// 压缩内容
var compressed bytes.Buffer
writer := zlib.NewWriter(&compressed)
_, err := writer.Write(content)
if err != nil {
writer.Close()
return "", err
}
writer.Close()
// 存储到 .git/objects 目录
objectDir := filepath.Join(".git", "objects", hashStr[:2])
os.MkdirAll(objectDir, 0755)
objectPath := filepath.Join(objectDir, hashStr[2:])
err = os.WriteFile(objectPath, compressed.Bytes(), 0644)
if err != nil {
return "", err
}
return hashStr, nil
}
// 读取 Git 对象(解压并读取)
func readGitObject(hash string) ([]byte, error) {
objectPath := filepath.Join(".git", "objects", hash[:2], hash[2:])
data, err := os.ReadFile(objectPath)
if err != nil {
return nil, err
}
// 解压
reader, err := zlib.NewReader(bytes.NewReader(data))
if err != nil {
return nil, err
}
defer reader.Close()
return io.ReadAll(reader)
}
func main() {
// 创建 Git blob 对象
content := []byte("Hello, Git!")
hash, err := createGitObject(GitBlob, content)
if err != nil {
fmt.Println("创建对象失败:", err)
return
}
fmt.Printf("创建对象:%s\n", hash)
// 读取 Git 对象
data, err := readGitObject(hash)
if err != nil {
fmt.Println("读取对象失败:", err)
return
}
// 解析内容(跳过头部)
nullIndex := bytes.IndexByte(data, 0)
if nullIndex >= 0 {
fmt.Printf("对象内容:%s\n", string(data[nullIndex+1:]))
}
}
6. 压缩级别对比
package main
import (
"bytes"
"compress/zlib"
"fmt"
"math/rand"
"time"
)
func benchmark(data []byte, level int) (compressedSize int, duration time.Duration) {
var buf bytes.Buffer
writer, _ := zlib.NewWriterLevel(&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 := []byte("Hello, World! This is a test of Zlib compression. " +
"Zlib is widely used in many applications. " +
"It provides good compression ratio and fast speed. " +
"Repeat this text many times to make it more compressible. ")
// 重复多次以增加数据量
for i := 0; i < 100; i++ {
data = append(data, data...)
}
levels := []struct {
name string
level int
}{
{"NoCompression", zlib.NoCompression},
{"BestSpeed", zlib.BestSpeed},
{"DefaultCompression", zlib.DefaultCompression},
{"BestCompression", zlib.BestCompression},
}
fmt.Printf("原始大小:%d 字节\n\n", len(data))
fmt.Println("压缩级别对比:")
fmt.Println("----------------------------------------")
for _, l := range levels {
size, duration := benchmark(data, l.level)
ratio := float64(size) / float64(len(data)) * 100
fmt.Printf("%-20s: %6d 字节 (%5.2f%%), 耗时 %v\n",
l.name, size, ratio, duration)
}
}
🔹 错误处理
常见错误
-
无效的 zlib 格式
- 说明:尝试解压非 zlib 格式的数据
- 处理方式:检查错误并验证数据格式
- 示例:
reader, err := zlib.NewReader(file) if err != nil { fmt.Println("无效的 zlib 格式:", err) }
-
Adler-32 校验失败
- 说明:压缩数据损坏
- 处理方式:读取时检查错误
- 示例:
data, err := io.ReadAll(reader) if err != nil { fmt.Println("校验失败:", err) }
-
写入器未关闭
- 说明:忘记调用 Close() 导致数据不完整
- 处理方式:始终使用 defer Close()
- 示例:
writer := zlib.NewWriter(dst) defer writer.Close() // 确保关闭
错误处理最佳实践
package main
import (
"compress/zlib"
"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)
}
}()
writer := zlib.NewWriter(dstFile)
defer writer.Close()
_, err = io.Copy(writer, srcFile)
if err != nil {
return fmt.Errorf("压缩失败:%w", err)
}
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)
}
}()
reader, err := zlib.NewReader(srcFile)
if err != nil {
return fmt.Errorf("创建解压