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