golang跨平台多格式压缩与归档处理插件库archives的使用
Golang跨平台多格式压缩与归档处理插件库archives的使用
介绍
mholt/archives 是一个跨平台、支持多种格式的Go库,用于处理归档和压缩格式,提供统一的API以及与io/fs兼容的虚拟文件系统。
功能特性
- 流式API
- 自动识别归档和压缩格式:
- 通过文件名
- 通过流头部探测
- 统一遍历目录、归档和其他文件作为io/fs文件系统:
- FileFS
- DirFS
- ArchiveFS
- 使用DeepFS无缝进入归档文件
- 压缩和解压文件
- 创建和提取归档文件
- 遍历归档文件
- 从归档中提取特定文件
- 向.tar和.zip归档中插入内容(追加)而无需重新创建整个归档
- 支持多种归档和压缩格式
- 读取受密码保护的7-Zip和RAR文件
- 可扩展(通过注册添加更多格式)
- 跨平台,静态二进制
- 纯Go实现(无cgo)
- 多线程Gzip
- 可调压缩级别
- 超快的Snappy实现(通过S2)
支持的压缩格式
- brotli (.br)
- bzip2 (.bz2)
- flate (.zip)
- gzip (.gz)
- lz4 (.lz4)
- lzip (.lz)
- minlz (.mz)
- snappy (.sz) 和 S2 (.s2)
- xz (.xz)
- zlib (.zz)
- zstandard (.zst)
支持的归档格式
- .zip
- .tar (包括压缩变体如.tar.gz)
- .rar (只读)
- .7z (只读)
安装
$ go get github.com/mholt/archives
使用示例
创建归档
ctx := context.TODO()
// 将磁盘文件映射到归档中的路径
files, err := archives.FilesFromDisk(ctx, nil, map[string]string{
"/path/on/disk/file1.txt": "file1.txt",
"/path/on/disk/file2.txt": "subfolder/file2.txt",
"/path/on/disk/file3.txt": "", // 放在归档根目录作为file3.txt
"/path/on/disk/file4.txt": "subfolder/", // 放在子文件夹作为file4.txt
"/path/on/disk/folder": "Custom Folder", // 递归添加内容
})
if err != nil {
return err
}
// 创建输出文件
out, err := os.Create("example.tar.gz")
if err != nil {
return err
}
defer out.Close()
// 使用CompressedArchive类型来gzip压缩tar包
format := archives.CompressedArchive{
Compression: archives.Gz{},
Archival: archives.Tar{},
}
// 创建归档
err = format.Archive(ctx, out, files)
if err != nil {
return err
}
提取归档
// 用于读取输入流的类型
var format archives.Zip
err := format.Extract(ctx, input, func(ctx context.Context, f archives.FileInfo) error {
// 在这里处理文件;或者如果你只想要特定文件或目录,
// 只需返回直到遇到所需的f.NameInArchive值
return nil
})
if err != nil {
return err
}
识别格式
// 除非你的流是io.Seeker,否则使用返回的stream值以确保重新读取Identify()期间消耗的字节
format, stream, err := archives.Identify(ctx, "filename.tar.zst", stream)
if err != nil {
return err
}
// 现在可以将format类型断言为你需要的类型
// 想要提取内容?
if ex, ok := format.(archives.Extractor); ok {
// ... 继续提取
}
// 或者可能是压缩的,你想解压它?
if decomp, ok := format.(archives.Decompressor); ok {
rc, err := decomp.OpenReader(unknownFile)
if err != nil {
return err
}
defer rc.Close()
// 从rc读取获取解压后的数据
}
虚拟文件系统
// filename可以是:
// - 文件夹("/home/you/Desktop")
// - 归档("example.zip")
// - 压缩归档("example.tar.gz")
// - 常规文件("example.txt")
// - 压缩的常规文件("example.txt.gz")
// 和/或最后一个参数可以是上述任何内容的流
fsys, err := archives.FileSystem(ctx, filename, nil)
if err != nil {
return err
}
压缩数据
// 包装底层writer w
compressor, err := archives.Zstd{}.OpenWriter(w)
if err != nil {
return err
}
defer compressor.Close()
// 写入compressor的数据将被压缩
解压数据
// 包装底层reader r
decompressor, err := archives.Snappy{}.OpenReader(r)
if err != nil {
return err
}
defer decompressor.Close()
// 从decompressor读取的数据将被解压
追加到tar和zip归档
tarball, err := os.OpenFile("example.tar", os.O_RDWR, 0644)
if err != nil {
return err
}
defer tarball.Close()
// 准备一个文本文件放在归档根目录
files, err := archives.FilesFromDisk(nil, map[string]string{
"/home/you/lastminute.txt": "",
})
err := archives.Tar{}.Insert(context.Background(), tarball, files)
if err != nil {
return err
}
遍历归档内容
fsys := &archives.DeepFS{Root: "/some/dir"}
err := fs.WalkDir(fsys, ".", func(fpath string, d fs.DirEntry, err error) error {
...
})
注意事项
-
对于.tar文件:由于tar文件的历史设计(针对顺序访问的磁带),它们不能高效地实现文件系统语义。文件系统本质上假设存在某种索引以支持随机访问,但tar文件需要从头开始读取才能访问末尾的内容。当归档被压缩时尤其慢。已实现优化来分摊ReadDir()调用,以便fs.WalkDir()只需扫描归档一次,但它们会使用更多内存。Open调用需要另一次扫描来查找文件。如果文件系统语义对你来说不重要,直接使用Tar.Extract()可能更高效。
-
与http.FileServer一起使用时:由于http.FileServer的工作方式,不要直接将其与压缩文件一起使用;而是像下面这样包装它:
fileServer := http.FileServer(http.FS(archiveFS))
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
// 禁用范围请求
writer.Header().Set("Accept-Ranges", "none")
request.Header.Del("Range")
// 禁用内容类型嗅探
ctype := mime.TypeByExtension(filepath.Ext(request.URL.Path))
writer.Header()["Content-Type"] = nil
if ctype != "" {
writer.Header().Set("Content-Type", ctype)
}
fileServer.ServeHTTP(writer, request)
})
更多关于golang跨平台多格式压缩与归档处理插件库archives的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang跨平台多格式压缩与归档处理插件库archives的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang跨平台多格式压缩与归档处理:archives库使用指南
archives是一个强大的Golang库,专门用于处理各种压缩和归档格式,支持跨平台操作。下面我将详细介绍如何使用这个库。
安装
首先安装archives库:
go get github.com/mholt/archiver/v3
基本使用
1. 压缩文件/目录
package main
import (
"github.com/mholt/archiver/v3"
"log"
)
func main() {
// 创建ZIP压缩文件
err := archiver.Archive([]string{"file1.txt", "folder"}, "archive.zip")
if err != nil {
log.Fatal(err)
}
// 创建TAR.GZ压缩文件
err = archiver.Archive([]string{"file1.txt", "folder"}, "archive.tar.gz")
if err != nil {
log.Fatal(err)
}
}
2. 解压文件
func extractExample() {
// 解压ZIP文件
err := archiver.Unarchive("archive.zip", "extracted")
if err != nil {
log.Fatal(err)
}
// 解压RAR文件
err = archiver.Unarchive("archive.rar", "extracted")
if err != nil {
log.Fatal(err)
}
}
支持的格式
archives库支持以下格式:
- ZIP
- TAR (包括.tar.gz, .tar.bz2, .tar.xz, .tar.lz4, .tar.sz)
- GZIP
- BZIP2
- LZ4
- SNAPPY
- XZ
- RAR (需要安装系统rar工具)
高级用法
1. 自定义压缩选项
func customCompression() {
// 创建自定义ZIP压缩器
z := archiver.Zip{
CompressionLevel: flate.BestCompression, // 最高压缩率
MkdirAll: true, // 自动创建目录
SelectiveCompression: true, // 选择性压缩
ContinueOnError: false, // 遇到错误是否继续
OverwriteExisting: true, // 覆盖已存在文件
ImplicitTopLevelFolder: false, // 是否包含顶层文件夹
}
err := z.Archive([]string{"file1.txt", "folder"}, "custom.zip")
if err != nil {
log.Fatal(err)
}
}
2. 流式处理大文件
func streamExample() {
// 创建TAR.GZ流式压缩
tgz := archiver.NewTarGz()
tgz.CompressionLevel = gzip.BestCompression
// 创建输出文件
out, err := os.Create("large.tar.gz")
if err != nil {
log.Fatal(err)
}
defer out.Close()
// 创建压缩器
err = tgz.Create(out)
if err != nil {
log.Fatal(err)
}
// 添加文件
file1, err := os.Open("largefile1.bin")
if err != nil {
log.Fatal(err)
}
defer file1.Close()
err = tgz.Write(archiver.File{
FileInfo: archiver.FileInfo{
Name: "largefile1.bin",
Mode: 0644,
Size: 0, // 自动计算
ModTime: time.Now(),
IsDir: false,
},
ReadCloser: file1,
})
if err != nil {
log.Fatal(err)
}
// 完成压缩
err = tgz.Close()
if err != nil {
log.Fatal(err)
}
}
3. 处理密码保护的ZIP文件
func passwordProtectedZip() {
// 创建密码保护的ZIP文件
z := archiver.Zip{
Password: "secret",
}
err := z.Archive([]string{"secret.txt"}, "protected.zip")
if err != nil {
log.Fatal(err)
}
// 解压密码保护的ZIP文件
uz := archiver.Zip{
Password: "secret",
}
err = uz.Unarchive("protected.zip", "extracted")
if err != nil {
log.Fatal(err)
}
}
性能优化建议
- 对于大文件,使用流式处理
- 根据需求选择合适的压缩级别
- 批量处理文件时考虑并发
错误处理
func handleErrors() {
err := archiver.Archive([]string{"nonexistent.txt"}, "error.zip")
if err != nil {
switch e := err.(type) {
case *archiver.ErrNotArchive:
log.Println("不是归档文件:", e)
case *archiver.ErrNoMatch:
log.Println("没有匹配的文件:", e)
case *archiver.ErrIllegalPath:
log.Println("非法路径:", e)
default:
log.Println("未知错误:", err)
}
}
}
总结
archives库为Golang提供了强大且易用的跨平台压缩和解压功能,支持多种格式,并提供了丰富的配置选项。无论是简单的压缩解压任务,还是需要精细控制的复杂场景,archives都能胜任。