mindoc/utils/ziptil/ziptil.go

241 lines
5.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package ziptil
import (
"archive/zip"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
//解压zip文件
//@param zipFile 需要解压的zip文件
//@param dest 需要解压到的目录
//@return err 返回错误
func Unzip(zipFile, dest string) (err error) {
dest = strings.TrimSuffix(dest, "/") + "/" // Make sure suffix with "/".
// 打开一个zip格式文件
r, err := zip.OpenReader(zipFile)
if err != nil {
return err
}
defer r.Close()
// 迭代压缩文件中的文件,打印出文件中的内容
for _, f := range r.File {
if !f.FileInfo().IsDir() {
path := filepath.Join(dest, f.Name)
// logs.Debug("file name: ", f.Name, ",dest:", dest,
// ",absolute path: ", filepath.Join(dest, f.Name),
// ",absolute dir: ", filepath.Dir(path),
// ",relative dir: ", filepath.Dir(f.Name))
if dir := filepath.Dir(path); !strings.Contains(dir, "__MACOSX") {
// This branch : 非目录且不包含__MACOSX目录
/* Resolve the Zip Slip problem.(Solution: The decompressed file must be in the DEST directory.)
References: https://github.com/golang/go/issues/25849
https://github.com/mholt/archiver/blob/e4ef56d48eb029648b0e895bb0b6a393ef0829c3/archiver.go#L110-L119 */
if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
return fmt.Errorf("illegal file path: %s", path)
}
os.MkdirAll(dir, 0777)
if fcreate, err := os.Create(path); err == nil {
if rc, err := f.Open(); err == nil {
io.Copy(fcreate, rc)
rc.Close() //不要用defer来关闭如果文件太多的话会报too many open files 的错误
fcreate.Close()
} else {
fcreate.Close()
return err
}
} else {
return err
}
}
}
}
return nil
}
//压缩文件
func Zip(source, target string) error {
zipFile, err := os.Create(target)
if err != nil {
return err
}
defer zipFile.Close()
archive := zip.NewWriter(zipFile)
defer archive.Close()
source = strings.Replace(source, "\\", "/", -1)
filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
path = strings.Replace(path, "\\", "/", -1)
if path == source {
return nil
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
header.Name = strings.TrimPrefix(strings.TrimPrefix(strings.Replace(path, "\\", "/", -1), source), "/")
if info.IsDir() {
header.Name += "/"
} else {
header.Method = zip.Deflate
}
writer, err := archive.CreateHeader(header)
if err != nil {
return err
}
if info.IsDir() {
return nil
}
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(writer, file)
return err
})
return err
}
////压缩指定文件或文件夹
////@param dest 压缩后的zip文件目标如/usr/local/hello.zip
////@param filepath 需要压缩的文件或者文件夹
////@return err 错误。如果返回错误则会删除dest文件
//func Zip(dest string, filepath ...string) (err error) {
// if len(filepath) == 0 {
// return errors.New("lack of file")
// }
// //创建文件
// fzip, err := os.Create(dest)
// if err != nil {
// return err
// }
// defer fzip.Close()
//
// var filelist []filetil.FileList
// for _, file := range filepath {
// if info, err := os.Stat(file); err == nil {
// if info.IsDir() { //目录,则扫描文件
// if f, _ := filetil.ScanFiles(file); len(f) > 0 {
// filelist = append(filelist, f...)
// }
// } else { //文件
// filelist = append(filelist, filetil.FileList{
// IsDir: false,
// Name: info.Name(),
// Path: file,
// })
// }
// } else {
// return err
// }
// }
// w := zip.NewWriter(fzip)
// defer w.Close()
// for _, file := range filelist {
// if !file.IsDir {
// if fw, err := w.Create(strings.TrimLeft(file.Path, "./")); err != nil {
// return err
// } else {
// if fileContent, err := ioutil.ReadFile(file.Path); err != nil {
// return err
// } else {
// if _, err = fw.Write(fileContent); err != nil {
// return err
// }
// }
// }
// }
// }
// return
//}
func Compress(dst string, src string) (err error) {
d, _ := os.Create(dst)
defer d.Close()
w := zip.NewWriter(d)
defer w.Close()
src = strings.Replace(src, "\\", "/", -1)
f, err := os.Open(src)
if err != nil {
return err
}
//prefix := src[strings.LastIndex(src,"/"):]
err = compress(f, "", w)
if err != nil {
return err
}
return nil
}
func compress(file *os.File, prefix string, zw *zip.Writer) error {
info, err := file.Stat()
if err != nil {
return err
}
if info.IsDir() {
if prefix != "" {
prefix = prefix + "/" + info.Name()
} else {
prefix = info.Name()
}
fileInfos, err := file.Readdir(-1)
if err != nil {
return err
}
for _, fi := range fileInfos {
f, err := os.Open(file.Name() + "/" + fi.Name())
if err != nil {
return err
}
err = compress(f, prefix, zw)
if err != nil {
return err
}
}
} else {
header, err := zip.FileInfoHeader(info)
if prefix != "" {
header.Name = prefix + "/" + header.Name
}
if err != nil {
return err
}
writer, err := zw.CreateHeader(header)
if err != nil {
return err
}
_, err = io.Copy(writer, file)
file.Close()
if err != nil {
return err
}
}
return nil
}