You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
6.3 KiB
252 lines
6.3 KiB
package util
|
|
|
|
import (
|
|
"archive/zip"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"fssc/config"
|
|
"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
|
|
}
|
|
|
|
// 监听的工作目录作为文件的结尾,然后取相对路径
|
|
// 在zip存档中设置文件的相对路径
|
|
header.Name, err = filepath.Rel(filepath.Dir(config.G.FilePath), path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 转换为Unix风格的路径分隔符
|
|
header.Name = filepath.ToSlash(header.Name)
|
|
|
|
// 目录需要拼上一个 "/" ,否则会出现一个和目录一样的文件在压缩包中
|
|
if info.IsDir() {
|
|
header.Name += "/"
|
|
} else {
|
|
// 将压缩方法设置为deflate
|
|
header.Method = zip.Deflate
|
|
}
|
|
// fmt.Printf("zip header:%v\n", 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)
|
|
}
|
|
|