package utils import ( "apsClient/pkg/logx" "archive/tar" "compress/gzip" "crypto/md5" "encoding/hex" "errors" "io" "io/ioutil" "log" "os" "os/exec" "path" "path/filepath" "strings" ) // FileName 待压缩的文件名 // DesPathName 压缩完之后存放的目录名 func Gzip(FilePathName, DesPathName string) error { // 清理路径字符串 FilePathName = path.Clean(FilePathName) // 要解压的文件名字 FileName := FilePathName index := strings.LastIndex(FilePathName, "\\") if index != -1 { FileName = FilePathName[index+1:] } logx.Infof("文件名称是", FileName) //创建存放压缩文件的路径(如果文件夹不存在) if !DirExists(DesPathName) { os.MkdirAll(DesPathName, 0777) } logx.Infof("创建文件") //创建压缩文件 DesFileName := DesPathName + "\\" + FileName + ".gz" fw, er := os.Create(DesFileName) if er != nil { return er } defer fw.Close() gw := gzip.NewWriter(fw) defer gw.Close() //读取文件内容 rd := make([]byte, 1024*1024) rd, err := ioutil.ReadFile(FilePathName) if err != nil { logx.Infof("读取文件内的数据出错 err:", err) return err } // 获取文件或目录信息 fi, err := os.Stat(FilePathName) if err != nil { logx.Infof("获取文件的详细信息出错 err :", err) return nil } gw.Name = fi.Name() gw.ModTime = fi.ModTime() _, err = gw.Write(rd) if err != nil { logx.Infof("写入压缩文件出错 err:", err) return err } err = gw.Flush() if err != nil { logx.Infof("gw.Flush() 出错 err:", err) return err } return nil } func UnGz(srcGz string, filePath string) error { fr, err := os.Open(srcGz) if err != nil { logx.Infof("open secGZ failed. err:", err) return err } gr, err := gzip.NewReader(fr) if err != nil { fr.Close() logx.Infof("create gzip.reader failed. err:", err) return err } index := strings.LastIndex(srcGz, ".") if index == -1 { gr.Close() fr.Close() logx.Infof("find . failed. err:", err) return err } fw, err := os.Create(filePath) if err != nil { gr.Close() fr.Close() logx.Infof("create file failed. err:", err) return err } // 写文件 _, err = io.Copy(fw, gr) if err != nil { fw.Close() gr.Close() fr.Close() logx.Infof("write file failed. err:", err) return err } fw.Close() gr.Close() fr.Close() //删除gz压缩文件 err = os.Remove(srcGz) if err != nil { logx.Infof("remove file failed. err:", err) return err } return nil } // 将文件或目录打包成 .tar 文件 // src 是要打包的文件或目录的路径 // dstTar 是要生成的 .tar 文件的路径 // failIfExiBst 标记如果 dstTar 文件存在,是否放弃打包,如果否,则会覆盖已存在的文件 func TarGz(src string, dstTar string, failIfExist bool) error { // 清理路径字符串 src = path.Clean(src) // 判断要打包的文件或目录是否存在 if !Exists(src) { return errors.New("要打包的文件或目录不存在:" + src) } // 判断目标文件是否存在 if FileExists(dstTar) { if failIfExist { // 不覆盖已存在的文件 return errors.New("目标文件已经存在:" + dstTar) } else { // 覆盖已存在的文件 if er := os.Remove(dstTar); er != nil { return er } } } // 创建空的目标文件 fw, er := os.Create(dstTar) if er != nil { return er } defer fw.Close() gw := gzip.NewWriter(fw) defer gw.Close() // 创建 tar.Writer,执行打包操作 tw := tar.NewWriter(gw) var err error defer func() { // 这里要判断 tw 是否关闭成功,如果关闭失败,则 .tar 文件可能不完整 if er := tw.Close(); er != nil { err = er } logx.Infof("defer err:", err) }() // 获取文件或目录信息 fi, er := os.Stat(src) if er != nil { return er } // 获取要打包的文件或目录的所在位置和名称 srcBase, srcRelative := path.Split(path.Clean(src)) // 开始打包 if fi.IsDir() { logx.Infof("第一层目录:", srcRelative) tarDir(srcBase, srcRelative, tw, fi) } else { tarFile(srcBase, srcRelative, tw, fi) } return nil } // 因为要执行遍历操作,所以要单独创建一个函数 func tarDir(srcBase, srcRelative string, tw *tar.Writer, fi os.FileInfo) (err error) { // 获取完整路径 srcFull := srcBase + srcRelative logx.Infof("srcFull:", srcFull) // 在结尾添加 "/" last := len(srcRelative) - 1 if srcRelative[last] != os.PathSeparator { srcRelative += string(os.PathSeparator) } // 获取 srcFull 下的文件或子目录列表 fis, er := ioutil.ReadDir(srcFull) if er != nil { return er } // 开始遍历 for _, fi := range fis { if fi.IsDir() { logx.Infof("下层目录") tarDir(srcBase, srcRelative+fi.Name(), tw, fi) } else { logx.Infof("是文件") tarFile(srcBase, srcRelative+fi.Name(), tw, fi) } } return nil } // 因为要在 defer 中关闭文件,所以要单独创建一个函数 func tarFile(srcBase, srcRelative string, tw *tar.Writer, fi os.FileInfo) (err error) { // 获取完整路径 srcFull := srcBase + srcRelative logx.Infof("文件的全路径", srcFull) // 写入文件信息 hdr, er := tar.FileInfoHeader(fi, "") if er != nil { return er } logx.Infof(srcRelative) hdr.Name = srcRelative logx.Infof("文件hdr.name", hdr.Name) if er = tw.WriteHeader(hdr); er != nil { return er } // 打开要打包的文件,准备读取 fr, er := os.Open(srcFull) if er != nil { return er } defer fr.Close() // 将文件数据写入 tw 中 if _, er = io.Copy(tw, fr); er != nil { return er } return nil } // 解包 可以解压,压缩文件里有文件夹的,也可以解压压缩文件里全是文件的 // srcGz待解包文件 // dstDir 解包之后存放的目录 func UnTarGz(srcGz string, dstDir string) error { dstDir = path.Clean(dstDir) + string(os.PathSeparator) //打开压缩文件 fr, err := os.Open(srcGz) if err != nil { return err } defer fr.Close() gw, err := gzip.NewReader(fr) defer gw.Close() // 创建 tar.Reader 对象,准备执行解包操作 // 可以用 tr.Next() 来遍历包中的文件 tr := tar.NewReader(gw) // 遍历包中的文件 for hdr, er := tr.Next(); er != io.EOF; hdr, er = tr.Next() { if er != nil { logx.Infof("--------- er:", er) return er } // 获取文件信息 fi := hdr.FileInfo() // 获取绝对路径 dstFullPath := dstDir + hdr.Name logx.Infof("--- dstFullPath:", dstFullPath) if hdr.Typeflag == tar.TypeDir { logx.Infof("--- type is floder") // 创建目录 os.MkdirAll(dstFullPath, fi.Mode().Perm()) // 设置目录权限 os.Chmod(dstFullPath, fi.Mode().Perm()) } else { logx.Infof(dstFullPath, "--- type is file") // 创建文件所在的目录 strtemp := dstFullPath[:strings.LastIndex(dstFullPath, "\\")+1] //os.MkdirAll(path.Dir(dstFullPath), os.ModePerm) os.MkdirAll(strtemp, os.ModePerm) // 将 tr 中的数据写入文件中 if er := unTarFile(dstFullPath, tr); er != nil { logx.Infof("unTarFile:", er) return er } // 设置文件权限 os.Chmod(dstFullPath, fi.Mode().Perm()) } } return nil } // 因为要在 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 } // 判断path是否存在 func Exists(path string) bool { // returns a FileInfo describing the named file // If there is an error, it will be of type *PathError _, err := os.Stat(path) if err != nil { // 检查这个error是否是文件/文件夹已存在的error if os.IsExist(err) { return true } return false } return true } // 判断文件是否存在 func FileExists(path string) bool { fileInfo, err := os.Stat(path) if err != nil { return false } // 不是dir,那就是file return !fileInfo.IsDir() } // 判断目录是否存在 func DirExists(path string) bool { fileInfo, err := os.Stat(path) if err != nil { return false } return fileInfo.IsDir() } func MakeIfNotExist(path string) { if !Exists(path) { os.MkdirAll(path, os.ModePerm) } } func CopyDirByCmd(src, dest string) (string, error) { cmd := exec.Command("cp", "-r", src, dest) outPut, err := cmd.Output() return string(outPut), err } // 文件夹复制 func CopyDir(src string, dest string) { original := src err := filepath.Walk(src, func(src string, f os.FileInfo, err error) error { if f == nil { return err } if f.IsDir() { CopyDir(f.Name(), dest+"/"+f.Name()) } else { logx.Infof("src:", src, "original:", original, "dest:", dest) destNew := strings.Replace(src, original, dest, -1) logx.Infof("destNew:", destNew) logx.Infof("CopyFile:" + src + " to " + destNew) CopyFile(src, destNew) } return nil }) if err != nil { logx.Infof("filepath.Walk() returned %v\n", err) } } // 大文件复制 func CopyFile(srcFileName string, dstFileName string) { //打开源文件 srcFile, err := os.Open(srcFileName) if err != nil { log.Fatalf("源文件读取失败,原因是:%v\n", err) } defer func() { err = srcFile.Close() if err != nil { log.Fatalf("源文件关闭失败,原因是:%v\n", err) } }() //创建目标文件,稍后会向这个目标文件写入拷贝内容 distFile, err := os.Create(dstFileName) if err != nil { log.Fatalf("目标文件创建失败,原因是:%v\n", err) } defer func() { err = distFile.Close() if err != nil { log.Fatalf("目标文件关闭失败,原因是:%v\n", err) } }() //定义指定长度的字节切片,每次最多读取指定长度 var tmp = make([]byte, 1024*4) //循环读取并写入 for { n, err := srcFile.Read(tmp) n, _ = distFile.Write(tmp[:n]) if err != nil { if err == io.EOF { //读到了文件末尾,并且写入完毕,任务完成返回(关闭文件的操作由defer来完成) return } else { log.Fatalf("拷贝过程中发生错误,错误原因为:%v\n", err) } } } } func FileMd5(path string) (string, error) { file, err := os.Open(path) if err != nil { return "", err } defer file.Close() _md5 := md5.New() if _, err := io.Copy(_md5, file); err != nil { return "", err } return hex.EncodeToString(_md5.Sum(nil)), nil } func UnTarGzByCmd(srcFile string, dstPath string) (string, error) { cmd := exec.Command("tar", "-zxvf", srcFile, "-C", dstPath) outPut, err := cmd.Output() return string(outPut), err }