package util import ( "archive/zip" "encoding/base64" "fmt" "io" "io/fs" "os" "path" "path/filepath" "strings" ) // 遍历目录下的文件 func GetDirFilePaths(dirPath string, relativeOnly bool) ([]string, error) { var filePaths []string err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if !info.IsDir() { if relativeOnly { fileName := filepath.Base(path) relativePath := filepath.ToSlash(filepath.Join(filepath.Base(dirPath), fileName)) filePaths = append(filePaths, relativePath) } else { filePaths = append(filePaths, filepath.ToSlash(path)) } } return nil }) if err != nil { return nil, err } return filePaths, nil } // dest:目的地址以及压缩文件名 eg:/data/logZip/2022-12-12-log.zip // paths:需要压缩的所有文件所组成的集合 func CompressToZip(dest string, currentPath string, paths []string) error { // fmt.Println("real path", currentPath) // 打开files 目录 filesPath := "" if dir, err := os.Getwd(); err == nil { filesPath = dir + "/files/" } if err := os.MkdirAll(filesPath, 0755); err != nil { fmt.Println(err.Error()) } // ToSlash 过滤windows的斜杠引起的bug zfile, err := os.Create(path.Join("./files", "/", dest)) if err != nil { return err } defer zfile.Close() zipWriter := zip.NewWriter(zfile) defer zipWriter.Close() // 遍历带压缩的目录信息 for _, src := range paths { // 替换文件名,并且去除前后 "\" 或 "/" // path = strings.Trim(path, string(filepath.Separator)) // 从配置中读取到源目录 src = path.Join(currentPath, "/", src) // 删除尾随路径(如果它是目录) src := strings.TrimSuffix(src, string(os.PathSeparator)) err = filepath.Walk(src, func(path string, info os.FileInfo, err error) error { if err != nil { return err } // 创建本地文件头 header, err := zip.FileInfoHeader(info) if err != nil { return err } // 将压缩方法设置为deflate header.Method = zip.Deflate // 在zip存档中设置文件的相对路径 header.Name, err = filepath.Rel(filepath.Dir(src), path) if err != nil { return err } // 目录需要拼上一个 "/" ,否则会出现一个和目录一样的文件在压缩包中 if info.IsDir() { // header.Name += string(os.PathSeparator) header.Name += "/" } else { // 替换一下分隔符,zip不支持 "\\" header.Name = strings.ReplaceAll(header.Name, "\\", "/") } // 创建写入头的writer headerWriter, err := zipWriter.CreateHeader(header) if err != nil { return err } if info.IsDir() { return nil } f, err := os.Open(path) if err != nil { return err } defer f.Close() _, err = io.Copy(headerWriter, f) return err }) if err != nil { return err } } // 存到指定位置 os.Rename(dest, path.Join("./files/", dest)) return nil } // 解压缩zip文件 // 这个方法必须是首字母大写的,才能被注册 // src: 需要解压的zip文件 func DecompressZip(zpFname string) error { // 下载文件 archive, err := zip.OpenReader(zpFname) if err != nil { return err } dir := filepath.Dir(zpFname) defer archive.Close() // 遍历目录 for _, f := range archive.File { filePath := filepath.Join(dir, f.Name) if f.FileInfo().IsDir() { os.MkdirAll(filePath, os.ModePerm) continue } // 父文件夹开始闯将目录 if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { return fmt.Errorf("failed to make directory (%v)", err) } // 文件原有模式 dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) if err != nil { return fmt.Errorf("failed to create file (%v)", err) } fileInArchive, err := f.Open() if err != nil { return fmt.Errorf("failed to open file in zip (%v)", err) } if _, err := io.Copy(dstFile, fileInArchive); err != nil { return fmt.Errorf("failed to copy file in zip (%v)", err) } dstFile.Close() fileInArchive.Close() } return nil } // Zip 压缩文件或目录 // @params dst io.Writer 压缩文件可写流 // @params src string 待压缩源文件/目录路径 func Zip(dst io.Writer, src string) error { // 强转一下路径 src = filepath.Clean(src) // 提取最后一个文件或目录的名称 baseFile := filepath.Base(src) // 判断src是否存在 _, err := os.Stat(src) if err != nil { return err } // 通文件流句柄创建一个ZIP压缩包 zw := zip.NewWriter(dst) // 延迟关闭这个压缩包 defer zw.Close() // 通过filepath封装的Walk来递归处理源路径到压缩文件中 return filepath.Walk(src, func(path string, info fs.FileInfo, err error) error { // 是否存在异常 if err != nil { return err } // 通过原始文件头信息,创建zip文件头信息 zfh, err := zip.FileInfoHeader(info) if err != nil { return err } // 赋值默认的压缩方法,否则不压缩 zfh.Method = zip.Deflate // 移除绝对路径 tmpPath := path index := strings.Index(tmpPath, baseFile) if index > -1 { tmpPath = tmpPath[index:] } // 替换文件名,并且去除前后 "\" 或 "/" tmpPath = strings.Trim(tmpPath, string(filepath.Separator)) // 替换一下分隔符,zip不支持 "\\" zfh.Name = strings.ReplaceAll(tmpPath, "\\", "/") // 目录需要拼上一个 "/" ,否则会出现一个和目录一样的文件在压缩包中 if info.IsDir() { zfh.Name += "/" } // 写入文件头信息,并返回一个ZIP文件写入句柄 zfw, err := zw.CreateHeader(zfh) if err != nil { return err } // 仅在他是标准文件时进行文件内容写入 if zfh.Mode().IsRegular() { // 打开要压缩的文件 sfr, err := os.Open(path) if err != nil { return err } defer sfr.Close() // 将srcFileReader拷贝到zipFilWrite中 _, err = io.Copy(zfw, sfr) if err != nil { return err } } // 搞定 return nil }) } // base64 encode // url safe func Bas64end(str string) string { // bdata:= return base64.URLEncoding.EncodeToString([]byte(str)) } // base64 url safe uneconde func Base64dec(bsstr string) string { dedc, _ := base64.URLEncoding.DecodeString(bsstr) return string(dedc) }