七叶笔记 » golang编程 » 压缩与解压tar.gz-golang

压缩与解压tar.gz-golang

后续会有更多的模式和算法以及区块链相关的,如果你是想学习go语言或者是对设计模式或者算法感兴趣亦或是区块链开发工作者,都可以关注一下。(微信公众号:Go语言之美。更多go语言知识信息等)。公众号会持续为大家分享更多干货。

努力的gopher

我们在平时经常用到 tar.gz 的解压与压缩,使用命令行大家都了解,tar -zcvf 与 tar -xvf 。今天我把我用go语言实现的压缩解压写下来,大家如果用到可以收藏下来,以后避免重复造轮子,个人觉得这个很值得在自己本地或者项目中保存起来,当作一个lib使用。不多说,下面是代码实现,本人目前也在用这个代码,还没有发现bug,如果有人发现bug请留言。

package fs

import (
 "archive/tar"
 "compress/gzip"
 "errors"
 "io"
 "os"
 "path"
 "path/filepath"
)

// UnTarGz takes a destination path and a reader; a tar reader loops over the tar.gz file
// creating the file structure at 'dst' along the way, and writing any files
func UnTarGz(dst string, r io.Reader) error {

 gzr, err := gzip.NewReader(r)
 if err !=  nil  {
 return err
 }
 defer func() {
 if e := gzr. Close (); e != nil {
 return
 }
 }()

 tr := tar.NewReader(gzr)

 for {
  Header , err := tr.Next()

 switch {

 // if no more files are found return
 case err == io. EOF :
 return nil

 // return any other error
 case err != nil:
 return err

 // if the header is nil, just skip it (not sure how this happens)
 case header == nil:
 continue
 }

 // the target location where the dir/file should be created
 target := filepath.Join(dst, header.Name)

 // the following switch could also be done using fi.Mode(), not sure if there
 // a benefit of using one vs. the other.
 // fi := header.FileInfo()

 // check the file type
 switch header.Typeflag {

 // if its a dir and it doesn't exist create it
 case tar.TypeDir:
 if _, err := os. Stat (target); err != nil {
 if err := os.MkdirAll(target, 0750); err != nil {
 return err
 }
 }

 // if it's a file create it
 case tar.TypeReg:
 f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
 if err != nil {
 return err
 }

 // copy over contents
 if _, err = io.Copy(f, tr); err != nil {
 return err
 }

 // manually close here after each file operation; defering would cause each file close
 // to wait until all operations have completed.
 if err = f.Close(); err != nil {
 return err
 }
 }
 }
}

// TarGz tar for srcPath and create destFile
// flag = 0,not contains srcPath dir, flag = 1, contains srcPath
func TarGz(srcPath string, destFile string, flag int) error {
 fw, err := os.Create(destFile)
 if err != nil {
 return err
 }
 defer fw.Close()

 // Gzip writer
 gw := gzip.NewWriter(fw)
 defer gw.Close()

 // Tar writer
 tw := tar.NewWriter(gw)
 defer tw.Close()

 // Check if it's a file or a directory
 f, err := os.Open(srcPath)
 if err != nil {
 return err
 }
 fi, err := f.Stat()
 if err != nil {
 return err
 }
 if fi.IsDir() {
 // handle source directory
 if flag == 0 {
 err := tarGzDir(srcPath, path.Base(""), tw)
 if err != nil {
 return err
 }
 } else if flag == 1 {
 err := tarGzFile(srcPath, path.Base(srcPath), tw, fi)
 if err != nil {
 return err
 }
 err = tarGzDir(srcPath, path.Base(srcPath), tw)
 if err != nil {
 return err
 }
 } else {
 return errors.New("Invlaid flag")
 }

 } else {
 // handle file directly
 if flag == 0 {
 err := tarGzFile(srcPath, path.Base(""), tw, fi)
 if err != nil {
 return err
 }
 } else if flag == 1 {
 err := tarGzFile(srcPath, path.Base(srcPath), tw, fi)
 if err != nil {
 return err
 }
 } else {
 return errors.New("Invlaid flag")
 }
 }

 return nil
}
func tarGzDir(srcDir string, recPath string, tw *tar.Writer) error {
 // Open source diretory
 dir, err := os.Open(srcDir)
 if err != nil {
 return err
 }
 defer dir.Close()

 // Get file info slice
 fis, err := dir.Readdir(0)
 if err != nil {
 return err
 }

 for _, fi := range fis {
 // Append path
 curPath := srcDir + "/" + fi.Name()

 err := tarGzFile(curPath, recPath+"/"+fi.Name(), tw, fi)
 if err != nil {
 return err
 }

 // Check it is directory or file
 if fi.IsDir() {
 // Directory
 // (Directory won't add unitl all subfiles are added)
 err := tarGzDir(curPath, recPath+"/"+fi.Name(), tw)
 if err != nil {
 return err
 }
 }
 }
 return nil
}
func tarGzFile(srcFile string, recPath string, tw *tar.Writer, fi os.FileInfo) error {
 if fi.IsDir() {
 // Create tar header
 hdr := new(tar.Header)
 // if last character of header name is '/' it also can be directory
 // but if you don't set Typeflag, error will occur when you untargz
 hdr.Name = recPath + "/"
 hdr.Typeflag = tar.TypeDir
 hdr.Size = 0
 hdr.Mode = int64(fi.Mode())
 hdr.ModTime = fi.ModTime()

 // Write hander
 err := tw.WriteHeader(hdr)
 if err != nil {
 return err
 }
 } else {
 // File reader
 fr, err := os.Open(srcFile)
 if err != nil {
 return err
 }
 defer fr.Close()

 // Create tar header
 hdr := new(tar.Header)
 hdr.Typeflag = tar.TypeReg
 hdr.Name = recPath
 hdr.Size = fi.Size()
 hdr.Mode = int64(fi.Mode())
 hdr.ModTime = fi.ModTime()

 // Write hander
 err = tw.WriteHeader(hdr)
 if err != nil {
 return err
 }

 // Write file data
 _, err = io.Copy(tw, fr)
 if err != nil {
 return err
 }
 }
 return nil
}

 

相关文章