Project Icon

archiver

跨平台多格式归档实用程序和Go库

archiver是一个跨平台的多格式归档实用程序和Go库。它提供流式API,可自动识别归档和压缩格式,统一遍历目录和文件。支持压缩、解压缩、创建和提取归档文件,兼容多种格式。该库具有可扩展性,采用纯Go实现,支持多线程Gzip,无需cgo依赖。

archiver Go 参考 Ubuntu-最新版 Macos-最新版 Windows-最新版

隆重推出 Archiver 4.0 - 一个跨平台、多格式的归档工具和 Go 库。这个通用的替代品集强大灵活的库和优雅的命令行界面于一体,可以替代多个特定平台或特定格式的归档工具。

:警告: v4 版本目前处于 Alpha 阶段。核心库 API 运行良好,但命令行工具尚未实现,大部分自动化测试也尚未完成。如果你需要使用 arc 命令,目前请继续使用 v3 版本。

特性

  • 面向流的 API
  • 自动识别归档和压缩格式:
    • 通过文件名
    • 通过文件头
  • 统一遍历目录、归档文件和任何其他文件,作为 io/fs 文件系统:
  • 压缩和解压缩文件
  • 创建和提取归档文件
  • 遍历归档文件
  • 从归档中仅提取特定文件
  • 插入(附加)到 .tar 和 .zip 归档
  • 读取受密码保护的 7-Zip 文件
  • 支持多种归档和压缩格式
  • 可扩展(通过注册即可添加更多格式)
  • 跨平台,静态二进制文件
  • 纯 Go 实现(无 cgo)
  • 多线程 Gzip
  • 可调节压缩级别
  • 自动将压缩文件添加到 zip 归档而无需重新压缩
  • 打开受密码保护的 RAR 归档

支持的压缩格式

  • brotli (.br)
  • bzip2 (.bz2)
  • flate (.zip)
  • gzip (.gz)
  • lz4 (.lz4)
  • lzip (.lz)
  • snappy (.sz)
  • xz (.xz)
  • zlib (.zz)
  • zstandard (.zst)

支持的归档格式

  • .zip
  • .tar(包括任何压缩变体,如 .tar.gz)
  • .rar(仅读取)
  • .7z(仅读取)

Tar 文件可以选择使用任何压缩格式进行压缩。

命令行使用

v4 版本即将推出。请参阅 v3 最新文档

库使用

$ go get github.com/mholt/archiver/v4

创建归档

创建归档可以完全不需要实际的磁盘或存储设备,因为你只需要传入一个 File 结构体 列表即可。

然而,从磁盘文件创建归档是很常见的,所以你可以使用 FilesFromDisk() 函数 来帮助你将磁盘上的文件名映射到归档中的路径。然后创建并自定义格式类型。

在这个例子中,我们将 4 个文件和一个目录(包括其内容,递归)添加到一个 .tar.gz 文件中:

// 将磁盘上的文件映射到归档中的路径
files, err := archiver.FilesFromDisk(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/",    // 放在 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 一个 tarball
// (压缩不是必需的;你可以直接使用 Tar)
format := archiver.CompressedArchive{
	Compression: archiver.Gz{},
	Archival:    archiver.Tar{},
}

// 创建归档
err = format.Archive(context.Background(), out, files)
if err != nil {
	return err
}

FilesFromDisk() 的第一个参数是一个可选的选项结构体,允许你自定义如何添加文件。

提取归档

提取归档、从归档中提取文件以及遍历归档都是同一个函数。

只需使用你的格式类型(例如 Zip)来调用 Extract()。你需要传入一个上下文(用于取消),输入流,你想从归档中提取的文件列表,以及一个处理每个文件的回调函数。

如果你想要所有文件,传入一个 nil 文件路径列表。

// 用于读取输入流的类型
format := archiver.Zip{}

// 我们想从归档中提取的文件列表;任何
// 目录都将包括其所有内容,除非
// 我们从处理程序返回 fs.SkipDir
// (将此设为 nil 以遍历归档中的所有文件)
fileList := []string{"file1.txt", "subfolder"}

handler := func(ctx context.Context, f archiver.File) error {
	// 处理文件
	return nil
}

err := format.Extract(ctx, input, fileList, handler)
if err != nil {
	return err
}

识别格式

有一个内容未知的输入流?没问题,archiver 可以为你识别它。它会尝试基于文件名和/或文件头(会窥视流)进行匹配:

format, input, err := archiver.Identify("filename.tar.zst", input)
if err != nil {
	return err
}
// 现在你可以将 format 类型断言为你需要的类型;
// 确保使用返回的流重新读取在 Identify() 期间消耗的字节

// 想要提取某些内容?
if ex, ok := format.(archiver.Extractor); ok {
	// ... 继续提取
}

// 或者也许它是压缩的,你想要解压缩?
if decom, ok := format.(archiver.Decompressor); ok {
	rc, err := decom.OpenReader(unknownFile)
	if err != nil {
		return err
	}
	defer rc.Close()

	// 从 rc 读取以获取解压缩的数据
}

Identify() 通过从流的开始读取任意数量的字节(恰好足以检查文件头)来工作。它会缓冲这些字节并返回一个新的读取器,让你可以重新读取它们。

虚拟文件系统

这是我最喜欢的功能。

假设你有一个文件。它可能是磁盘上的一个真实目录、一个归档文件、一个压缩归档文件,或者任何其他常规文件。你并不真的关心它是什么;你只是想无论它是什么都能统一使用它。

使用 archiver 简单地创建一个文件系统:

// filename 可能是:
// - 一个文件夹 ("/home/you/Desktop")
// - 一个归档文件 ("example.zip")
// - 一个压缩归档文件 ("example.tar.gz")
// - 一个常规文件 ("example.txt")
// - 一个压缩的常规文件 ("example.txt.gz")
fsys, err := archiver.FileSystem(filename)
if err != nil {
	return err
}

这是一个功能齐全的 fs.FS,所以你可以打开文件和读取目录,无论输入是什么类型的文件。

例如,要打开一个特定的文件:

f, err := fsys.Open("file")
if err != nil {
	return err
}
defer f.Close()

如果你打开了一个常规文件,你可以从中读取。如果是压缩文件,读取时会自动解压缩。

如果你打开了一个目录,你可以列出其内容:

if dir, ok := f.(fs.ReadDirFile); ok {
	// 0 获取所有条目,但你可以传入 > 0 来分页
	entries, err := dir.ReadDir(0)
	if err != nil {
		return err
	}
	for _, e := range entries {
		fmt.Println(e.Name())
	}
}

或者这样获取目录列表:

entries, err := fsys.ReadDir("Playlists")
if err != nil {
	return err
}
for _, e := range entries {
	fmt.Println(e.Name())
}

或者你可能想遍历文件系统的全部或部分,但跳过名为 .git 的文件夹:

err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
	if err != nil {
		return err
	}
	if path == ".git" {
		return fs.SkipDir
	}
	fmt.Println("Walking:", path, "Dir?", d.IsDir())
	return nil
})
if err != nil {
	return err
}

http.FileServer 一起使用

它可以与 http.FileServer 一起使用,在浏览器中浏览归档文件和目录。但是,由于 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)
})

如果无法从文件名推断内容类型,http.FileServer 默认会尝试嗅探 Content-Type。为此,http 包会尝试从文件读取,然后再 Seek 回文件开头,这是库目前无法实现的。对范围请求也是如此。由于依赖项的限制,archiver 目前不支持在归档文件中进行 Seek 操作。

如果需要内容类型,你可以自己注册它

压缩数据

压缩格式让你可以打开写入器来压缩数据:

// 包装底层写入器 w
compressor, err := archiver.Zstd{}.OpenWriter(w)
if err != nil {
	return err
}
defer compressor.Close()

// 写入 compressor 的数据将被压缩

解压数据

同样,压缩格式让你可以打开读取器来解压数据:

// 包装底层读取器 r
decompressor, err := archiver.Brotli{}.OpenReader(r)
if err != nil {
	return err
}
defer decompressor.Close()

// 从 decompressor 读取的数据将被解压

向 tarball 和 zip 归档文件追加内容

通过在 tar 或 zip 流上调用 Insert(),可以在不创建全新归档的情况下向 Tar 和 Zip 归档文件追加内容。但是,对于 tarball,这要求 tarball 不被压缩(由于修改压缩字典的复杂性)。

以下是一个向磁盘上的 tarball 追加文件的例子:

tarball, err := os.OpenFile("example.tar", os.O_RDWR, 0644)
if err != nil {
	return err
}
defer tarball.Close()

// 为归档的根目录准备一个文本文件
files, err := archiver.FilesFromDisk(nil, map[string]string{
	"/home/you/lastminute.txt": "",
})

err := archiver.Tar{}.Insert(context.Background(), tarball, files)
if err != nil {
	return err
}

向 Zip 归档文件插入内容的代码类似,只是你需要在 Zip 类型上调用 Insert() 而不是 Tar。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号