qinglong-go/utils/tar.go

86 lines
2.2 KiB
Go
Raw Normal View History

package utils
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"os"
"path/filepath"
)
func UnTar(dst, src string) (err error) {
// 打开准备解压的 tar 包
fr, err := os.Open(src)
if err != nil {
return
}
defer fr.Close()
// 将打开的文件先解压
gr, err := gzip.NewReader(fr)
if err != nil {
return
}
defer gr.Close()
// 通过 gr 创建 tar.Reader
tr := tar.NewReader(gr)
// 现在已经获得了 tar.Reader 结构了,只需要循环里面的数据写入文件就可以了
for {
hdr, err := tr.Next()
switch {
case err == io.EOF:
return nil
case err != nil:
return err
case hdr == nil:
continue
}
// 处理下保存路径,将要保存的目录加上 header 中的 Name
// 这个变量保存的有可能是目录,有可能是文件,所以就叫 FileDir 了……
dstFileDir := filepath.Join(dst, hdr.Name)
// 根据 header 的 Typeflag 字段,判断文件的类型
switch hdr.Typeflag {
case tar.TypeDir: // 如果是目录时候,创建目录
// 判断下目录是否存在,不存在就创建
if b := ExistDir(dstFileDir); !b {
// 使用 MkdirAll 不使用 Mkdir ,就类似 Linux 终端下的 mkdir -p
// 可以递归创建每一级目录
if err := os.MkdirAll(dstFileDir, 0775); err != nil {
return err
}
}
case tar.TypeReg: // 如果是文件就写入到磁盘
// 创建一个可以读写的文件,权限就使用 header 中记录的权限
// 因为操作系统的 FileMode 是 int32 类型的hdr 中的是 int64所以转换下
file, err := os.OpenFile(dstFileDir, os.O_CREATE|os.O_RDWR, os.FileMode(hdr.Mode))
if err != nil {
return err
}
n, err := io.Copy(file, tr)
if err != nil {
return err
}
// 将解压结果输出显示
fmt.Printf("成功解压: %s , 共处理了 %d 个字符\n", dstFileDir, n)
// 不要忘记关闭打开的文件,因为它是在 for 循环中,不能使用 defer
// 如果想使用 defer 就放在一个单独的函数中
file.Close()
}
}
return nil
}
// 判断目录是否存在
func ExistDir(dirname string) bool {
fi, err := os.Stat(dirname)
return (err == nil || os.IsExist(err)) && fi.IsDir()
}