mirror of https://github.com/go-sonic/sonic.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
4.9 KiB
Go
230 lines
4.9 KiB
Go
package util
|
|
|
|
import (
|
|
"archive/zip"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/go-sonic/sonic/util/xerr"
|
|
)
|
|
|
|
func ZipFile(dst string, srcs ...string) (err error) {
|
|
// 创建准备写入的文件
|
|
fw, err := os.Create(dst)
|
|
if err != nil {
|
|
return xerr.NoType.Wrap(err).WithMsg("create zip file err")
|
|
}
|
|
defer func() {
|
|
if err = fw.Close(); err != nil {
|
|
err = xerr.NoType.Wrap(err).WithMsg("close file")
|
|
}
|
|
}()
|
|
// 通过 fw 来创建 zip.Write
|
|
zw := zip.NewWriter(fw)
|
|
defer func() {
|
|
if err = zw.Close(); err != nil {
|
|
err = xerr.NoType.Wrap(err).WithMsg("close zip file")
|
|
}
|
|
}()
|
|
|
|
for _, src := range srcs {
|
|
// 下面来将文件写入 zw ,因为有可能会有很多个目录及文件,所以递归处理
|
|
err = filepath.Walk(src, func(path string, fi os.FileInfo, errBack error) (err error) {
|
|
if errBack != nil {
|
|
return errBack
|
|
}
|
|
|
|
// 通过文件信息,创建 zip 的文件信息
|
|
fh, err := zip.FileInfoHeader(fi)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if path == src {
|
|
fh.Name = filepath.Base(src)
|
|
} else {
|
|
fh.Name = filepath.Join(filepath.Base(src), strings.TrimPrefix(path, src))
|
|
}
|
|
// 替换文件信息中的文件名
|
|
fh.Name = strings.TrimPrefix(fh.Name, string(filepath.Separator))
|
|
|
|
// 这步开始没有加,会发现解压的时候说它不是个目录
|
|
if fi.IsDir() {
|
|
fh.Name += "/"
|
|
}
|
|
|
|
// 写入文件信息,并返回一个 Write 结构
|
|
w, err := zw.CreateHeader(fh)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// 检测,如果不是标准文件就只写入头信息,不写入文件数据到 w
|
|
// 如目录,也没有数据需要写
|
|
if !fh.Mode().IsRegular() {
|
|
return nil
|
|
}
|
|
|
|
// 打开要压缩的文件
|
|
fr, err := os.Open(path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer fr.Close()
|
|
|
|
// 将打开的文件 Copy 到 w
|
|
_, err = io.Copy(w, fr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
// 输出压缩的内容
|
|
|
|
return err
|
|
})
|
|
if err != nil {
|
|
return xerr.NoType.Wrap(err).WithMsg("zip file err")
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func Unzip(src string, dest string) ([]string, error) {
|
|
r, err := zip.OpenReader(src)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer r.Close()
|
|
|
|
filenames := make([]string, 0, len(r.File))
|
|
for _, f := range r.File {
|
|
// Store filename/path for returning and using later on
|
|
fpath := filepath.Join(dest, f.Name)
|
|
|
|
// Check for ZipSlip. More Info: http://bit.ly/2MsjAWE
|
|
if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) {
|
|
return filenames, fmt.Errorf("%s: illegal file path", fpath)
|
|
}
|
|
|
|
filenames = append(filenames, fpath)
|
|
|
|
if f.FileInfo().IsDir() {
|
|
// Make Folder
|
|
err := os.MkdirAll(fpath, os.ModePerm)
|
|
if err != nil {
|
|
return nil, xerr.WithStatus(err, xerr.StatusInternalServerError)
|
|
}
|
|
continue
|
|
}
|
|
|
|
// Make File
|
|
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
|
|
return filenames, err
|
|
}
|
|
|
|
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
|
if err != nil {
|
|
return filenames, err
|
|
}
|
|
|
|
rc, err := f.Open()
|
|
if err != nil {
|
|
return filenames, err
|
|
}
|
|
|
|
_, err = io.Copy(outFile, rc)
|
|
|
|
// Close the file without defer to close before next iteration of loop
|
|
outFile.Close()
|
|
rc.Close()
|
|
|
|
if err != nil {
|
|
return filenames, err
|
|
}
|
|
}
|
|
return filenames, nil
|
|
}
|
|
|
|
func CopyDir(srcPath, desPath string) error {
|
|
if srcInfo, err := os.Stat(srcPath); err != nil {
|
|
return err
|
|
} else if !srcInfo.IsDir() {
|
|
return xerr.WithMsg(nil, "src is not dir")
|
|
}
|
|
|
|
if err := MakeDir(desPath); err != nil {
|
|
return err
|
|
}
|
|
if desInfo, err := os.Stat(desPath); err != nil {
|
|
return err
|
|
} else if !desInfo.IsDir() {
|
|
return xerr.WithMsg(nil, "dest is not dir")
|
|
}
|
|
|
|
if strings.TrimSpace(srcPath) == strings.TrimSpace(desPath) {
|
|
return xerr.WithMsg(nil, "srcPath=destPath")
|
|
}
|
|
|
|
err := filepath.Walk(srcPath, func(path string, f os.FileInfo, err error) error {
|
|
if f == nil {
|
|
return err
|
|
}
|
|
|
|
if path == srcPath {
|
|
return nil
|
|
}
|
|
|
|
destNewPath := strings.ReplaceAll(path, srcPath, desPath)
|
|
|
|
if !f.IsDir() {
|
|
if _, err = CopyFile(path, destNewPath); err != nil {
|
|
return err
|
|
}
|
|
} else if !FileIsExisted(destNewPath) {
|
|
return MakeDir(destNewPath)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func CopyFile(src, des string) (written int64, err error) {
|
|
srcFile, err := os.Open(src)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer srcFile.Close()
|
|
|
|
fi, _ := srcFile.Stat()
|
|
perm := fi.Mode()
|
|
|
|
desFile, err := os.OpenFile(des, os.O_RDWR|os.O_CREATE|os.O_TRUNC, perm)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer desFile.Close()
|
|
|
|
return io.Copy(desFile, srcFile)
|
|
}
|
|
|
|
func FileIsExisted(filename string) bool {
|
|
existed := true
|
|
if _, err := os.Stat(filename); err != nil && os.IsNotExist(err) {
|
|
existed = false
|
|
}
|
|
return existed
|
|
}
|
|
|
|
func MakeDir(dir string) error {
|
|
if !FileIsExisted(dir) {
|
|
if err := os.MkdirAll(dir, 0o777); err != nil { // os.ModePerm
|
|
fmt.Println("MakeDir failed:", err)
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|