86 lines
2.2 KiB
Go
86 lines
2.2 KiB
Go
|
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()
|
|||
|
}
|