<!-- lang: cpp -->
package main
import ( "archive/tar" "io" "io/ioutil" "log" "os" "path" )
func main() { //TarDynamicContent() //UnTar("D:/home/mytar.tar", "D:/home/mytar/") TarExistFile("D:/home/gif/111.gif") }
func UnTar(srcTar string, dstDir string) { // 清理路径字符串 dstDir = path.Clean(dstDir) + "/"
// 打开要解包的文件
fr, er := os.Open(srcTar)
if er != nil {
log.Fatalln(er)
}
defer fr.Close()
// 创建 tar.Reader,准备执行解包操作
tr := tar.NewReader(fr)
// 遍历包中的文件
for hdr, er := tr.Next(); er != io.EOF; hdr, er = tr.Next() {
if er != nil {
log.Fatalln(er)
continue
}
// 获取文件信息
fi := hdr.FileInfo()
// 获取绝对路径
dstFullPath := dstDir + hdr.Name
if hdr.Typeflag == tar.TypeDir {
// 创建目录
os.MkdirAll(dstFullPath, fi.Mode().Perm())
// 设置目录权限
os.Chmod(dstFullPath, fi.Mode().Perm())
} else {
// 创建文件所在的目录
os.MkdirAll(path.Dir(dstFullPath), os.ModePerm)
// 将 tr 中的数据写入文件中
if er := unTarFile(dstFullPath, tr); er != nil {
log.Fatalln(er)
}
// 设置文件权限
os.Chmod(dstFullPath, fi.Mode().Perm())
}
}
}
// 因为要在 defer 中关闭文件,所以要单独创建一个函数 func unTarFile(dstFile string, tr *tar.Reader) error { // 创建空文件,准备写入解包后的数据 fw, er := os.Create(dstFile) if er != nil { return er } defer fw.Close()
// 写入解包后的数
_, er = io.Copy(fw, tr)
if er != nil {
return er
}
return nil
}
func TarExistFile(srcPath string) { // 创建空的目标文件 fw, _ := os.Create("D:/home/mytar-file.tar") defer fw.Close()
// 创建 tar.Writer,执行打包操作
tw := tar.NewWriter(fw)
defer func() {
tw.Flush()
tw.Close()
}()
// 获取文件或目录信息
fi, _ := os.Stat(srcPath)
// 获取要打包的文件或目录的所在位置(parent dir) 和 名称
parentDir, dirOrFileName := path.Split(path.Clean(srcPath))
// 开始打包
if fi.IsDir() {
tarDir(parentDir, dirOrFileName, tw, fi)
} else {
tarFile(parentDir, dirOrFileName, tw, fi)
}
}
// 因为要执行遍历操作,所以要单独创建一个函数 func tarDir(parentDir, dirName string, tw *tar.Writer, fi os.FileInfo) { // 写入目录信息 if len(dirName) > 0 { hdr, _ := tar.FileInfoHeader(fi, "") hdr.Name = dirName tw.WriteHeader(hdr) }
dirFull := parentDir + dirName + "/"
// 获取 srcFull 下的文件或子目录列表
fis, _ := ioutil.ReadDir(dirFull)
// 开始遍历
for _, nfi := range fis {
if nfi.IsDir() {
tarDir(parentDir, dirName+"/"+nfi.Name(), tw, nfi)
} else {
tarFile(parentDir, dirName+"/"+nfi.Name(), tw, nfi)
}
}
}
// 因为要在 defer 中关闭文件,所以要单独创建一个函数 func tarFile(fileDir, filename string, tw *tar.Writer, fi os.FileInfo) { // 获取完整路径 filepath := fileDir + filename log.Println("file: ", filepath)
// 写入文件信息
hdr, _ := tar.FileInfoHeader(fi, "")
hdr.Name = filename
tw.WriteHeader(hdr)
fb, _ := ioutil.ReadFile(filepath)
tw.Write(fb)
}
func TarDynamicContent() { // 创建空的目标文件 fw, er := os.Create("D:/home/mytar.tar") if er != nil { log.Fatalln(er) } defer fw.Close()
// 创建 tar.Writer,执行打包操作
tw := tar.NewWriter(fw)
defer func() {
tw.Flush()
// 这里要判断 tw 是否关闭成功,如果关闭失败,则 .tar 文件可能不完整
if er := tw.Close(); er != nil {
log.Fatalln(er)
}
}()
//要打包的内容
var files = []struct {
Name, Body string
}{
{"readme.txt", "thie archive contains some text files"},
{"gopher.txt", "Gopher names:\nGeorge \nGeoffrey\nGonzo"},
{"todo.txt", "Get animal handling licence"},
}
//写入tar
for _, file := range files {
hdr := &tar.Header{
Name: file.Name,
Size: int64(len(file.Body)),
}
if err := tw.WriteHeader(hdr); err != nil {
log.Fatalln(err)
}
if _, err := tw.Write([]byte(file.Body)); err != nil {
log.Fatalln(err)
}
}
}