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.
sonic/util/file.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
}