Skip to content

压缩算法

常用于HTTP响应压缩

go
package main

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io"
	"log"
)

func main() {
	// 加点长度让压缩效果更明显
	original := "这是一段需要被压缩的测试数据, Go 语言的压缩功能非常强大且易用" + string(make([]byte, 1000))

	// 1. 压缩
	var buf bytes.Buffer
	writer := gzip.NewWriter(&buf)

	_, err := writer.Write([]byte(original))
	if err != nil {
		log.Fatal("[压缩失败]", err)
	}

	writer.Close()                // 必须关闭 writer 以写入结束标记(EOF)
	compressedData := buf.Bytes() // 压缩后的数据
	fmt.Printf("原始大小: %d 字节\n", len(original))
	fmt.Printf("压缩后大小: %d 字节", len(compressedData))

	// 2. 解压
	reader, err := gzip.NewReader(bytes.NewReader(compressedData))
	if err != nil {
		log.Fatal("[解压失败]", err)
	}
	defer reader.Close() // 关闭 reader 以释放资源

	decompressed, err := io.ReadAll(reader)
	if err != nil {
		log.Fatal("[读取失败]", err)
	}

	// 3.测试
	if string(decompressed) == original {
		fmt.Println("解压成功, 数据一致")
	} else {
		fmt.Println("数据不一致!")
	}
}

打包

常用于数据备份/或日志归档

go
package main

import (
	"archive/zip"
	"fmt"
	"io"
	"os"
	"path/filepath"
)

func ZipDirs(zipOutput string, dirs []string) error {
	// 创建 zip 文件
	zipFile, err := os.Create(zipOutput)
	if err != nil {
		return fmt.Errorf("创建 zip 文件失败: %w", err)
	}
	defer zipFile.Close()

	// 创建 zip 写入器
	zipWriter := zip.NewWriter(zipFile)
	defer zipWriter.Close()

	// 遍历每个目录
	for _, dir := range dirs {
		err := filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
			if err != nil {
				return err
			}

			// 跳过目录本身(只处理文件)
			if d.IsDir() {
				return nil
			}

			// 打开源文件
			srcFile, err := os.Open(path)
			if err != nil {
				return err
			}
			defer srcFile.Close()

			// 获取文件信息
			info, err := d.Info()
			if err != nil {
				return err
			}

			// 创建 zip 文件头,保留相对路径
			relPath, err := filepath.Rel(filepath.Dir(dir), path)
			if err != nil {
				return err
			}
			// 统一使用正斜杠
			relPath = filepath.ToSlash(relPath)

			header, err := zip.FileInfoHeader(info)
			if err != nil {
				return err
			}
			header.Name = relPath
			header.Method = zip.Deflate // 使用压缩

			// 创建 zip 中的文件
			writer, err := zipWriter.CreateHeader(header)
			if err != nil {
				return err
			}

			// 写入文件内容
			_, err = io.Copy(writer, srcFile)
			return err
		})
		if err != nil {
			return fmt.Errorf("处理目录 %s 时出错: %w", dir, err)
		}
	}

	return nil
}

func main() {
	// 要打包的目录列表
	dirs := []string{
		"./project/src",
		"./project/config",
		"./project/docs",
	}

	// 输出 zip 文件路径
	outputZip := "./project_backup.zip"

	err := ZipDirs(outputZip, dirs)
	if err != nil {
		fmt.Printf("打包失败: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("成功打包为: %s\n", outputZip)

	// 可选:显示压缩包内容
	printZipContents(outputZip)
}

// printZipContents 打印 zip 文件中的内容列表
func printZipContents(zipPath string) {
	reader, err := zip.OpenReader(zipPath)
	if err != nil {
		fmt.Printf("无法打开 zip 文件: %v\n", err)
		return
	}
	defer reader.Close()

	fmt.Println("\n压缩包内容:")
	for _, file := range reader.File {
		fmt.Printf("  %s (%d 字节)\n", file.Name, file.UncompressedSize64)
	}
}

Released under the MIT License.