
本文档详细介绍了如何使用 Go 语言创建一个包含完整目录结构的 tar.gz 压缩文件。通过递归遍历目录,并将每个文件和目录的完整路径信息添加到 tar 归档中,最终生成一个可以在 Linux 等系统上正确解压并还原目录结构的压缩包。本文提供代码示例,并解释了关键步骤,帮助开发者理解并实现该功能。
创建 Tar Gzip 文件的 Go 语言教程
本教程将指导你如何使用 Go 语言创建一个 tar.gz 文件,该文件能够完整地保留目录结构。核心思路是递归遍历目标目录,并将每个文件或目录的完整路径添加到 tar 归档中。
核心代码实现
以下代码展示了如何实现将目录及其内容压缩到 tar.gz 文件的功能。
package main
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strings"
)
func handleError(_e error) {
if _e != nil {
log.Fatal(_e)
}
}
func TarGzWrite(_path string, tw *tar.Writer, fi os.FileInfo) {
fr, err := os.Open(_path)
handleError(err)
defer fr.Close()
h := new(tar.Header)
h.Name = _path // 使用完整路径
h.Size = fi.Size()
h.Mode = int64(fi.Mode())
h.ModTime = fi.ModTime()
err = tw.WriteHeader(h)
handleError(err)
_, err = io.Copy(tw, fr)
handleError(err)
}
func IterDirectory(dirPath string, tw *tar.Writer) {
dir, err := os.Open(dirPath)
handleError(err)
defer dir.Close()
fis, err := dir.Readdir(0)
handleError(err)
for _, fi := range fis {
curPath := filepath.Join(dirPath, fi.Name()) // 使用 filepath.Join 构建路径
if fi.IsDir() {
// 添加目录本身
hdr := &tar.Header{
Name: curPath,
Mode: 0755, // 目录权限
ModTime: fi.ModTime(),
Typeflag: tar.TypeDir,
}
if err := tw.WriteHeader(hdr); err != nil {
log.Fatal(err)
}
IterDirectory(curPath, tw) // 递归调用
} else {
fmt.Printf("adding... %s\n", curPath)
TarGzWrite(curPath, tw, fi)
}
}
}
func TarGz(outFilePath string, inPath string) {
// file write
fw, err := os.Create(outFilePath)
handleError(err)
defer fw.Close()
// gzip write
gw := gzip.NewWriter(fw)
defer gw.Close()
// tar write
tw := tar.NewWriter(gw)
defer tw.Close()
// 添加根目录
fi, err := os.Stat(inPath)
handleError(err)
hdr, err := tar.FileInfoHeader(fi, fi.Name())
handleError(err)
hdr.Name = inPath
if err := tw.WriteHeader(hdr); err != nil {
log.Fatal(err)
}
IterDirectory(inPath, tw)
fmt.Println("tar.gz ok")
}
func main() {
targetFilePath := "test.tar.gz"
inputDirPath := "test/"
TarGz(targetFilePath, strings.TrimRight(inputDirPath, "/"))
fmt.Println("Hello, World")
}代码解释
- TarGzWrite 函数: 此函数负责将单个文件写入 tar 归档。关键在于 h.Name = _path 这一行,它使用文件的完整路径作为 tar 归档中的文件名,从而保留目录结构。
- IterDirectory 函数: 此函数递归地遍历目录。对于每个目录,它递归调用自身。对于每个文件,它调用 TarGzWrite 函数将其写入 tar 归档。特别要注意的是,需要为目录本身添加 tar.Header,并将 Typeflag 设置为 tar.TypeDir。
- TarGz 函数: 此函数是入口函数,它创建输出文件、gzip 写入器和 tar 写入器,然后调用 IterDirectory 函数开始遍历和写入。添加根目录是必要的,否则解压时会缺少根目录。
使用示例
假设你的目录结构如下:
test/
├── 0.txt
└── 1
└── 1.txt运行上述代码后,会生成 test.tar.gz 文件。使用 tar -tvf test.tar.gz 命令查看内容,你应该看到类似如下的输出:
drwxr-xr-x 0 0 0 0 2023-10-27 14:55 test/ -rw-r--r-- 0 0 0 0 2023-10-27 14:55 test/0.txt drwxr-xr-x 0 0 0 0 2023-10-27 14:55 test/1/ -rw-r--r-- 0 0 0 0 2023-10-27 14:55 test/1/1.txt
这表明 tar.gz 文件中正确地保留了目录结构。
注意事项
- 路径处理: 使用 filepath.Join 来构建路径,以确保跨平台兼容性。
- 目录权限: 在创建目录的 tar.Header 时,需要设置适当的权限 (Mode) 和 Typeflag。
- 错误处理: 务必进行充分的错误处理,以确保程序的健壮性。
- 添加根目录: 务必在递归遍历前,添加根目录,否则解压时会缺少根目录。
总结
通过以上步骤,你可以使用 Go 语言创建一个包含完整目录结构的 tar.gz 文件。关键在于正确地处理路径,并在 tar 归档中包含每个文件和目录的完整路径信息。 希望本教程能够帮助你理解并实现该功能。










