package utils import ( "archive/zip" "fmt" "io" "io/fs" "log" "os" "path" "path/filepath" "strings" ) func Zip(zipPath string, paths ...string) error { // Create zip file and it's parent dir. if err := os.MkdirAll(filepath.Dir(zipPath), os.ModePerm); err != nil { return err } archive, err := os.Create(zipPath) if err != nil { return err } defer archive.Close() // New zip writer. zipWriter := zip.NewWriter(archive) defer zipWriter.Close() // Traverse the file or directory. for _, rootPath := range paths { // Remove the trailing path separator if path is a directory. rootPath = strings.TrimSuffix(rootPath, string(os.PathSeparator)) // Visit all the files or directories in the tree. err = filepath.Walk(rootPath, walkFunc(rootPath, zipWriter)) if err != nil { return err } } return nil } func walkFunc(rootPath string, zipWriter *zip.Writer) filepath.WalkFunc { return func(path string, info fs.FileInfo, err error) error { if err != nil { return err } // If a file is a symbolic link it will be skipped. if info.Mode()&os.ModeSymlink != 0 { return nil } // Create a local file header. header, err := zip.FileInfoHeader(info) if err != nil { return err } // Set compression method. header.Method = zip.Deflate // Set relative path of a file as the header name. header.Name, err = filepath.Rel(rootPath, path) if err != nil { return err } if info.IsDir() { header.Name += string(os.PathSeparator) } // Create writer for the file header and save content of the file. headerWriter, err := zipWriter.CreateHeader(header) if err != nil { return err } if info.IsDir() { return nil } fmt.Println(header.Name) f, err := os.Open(path) if err != nil { return err } defer f.Close() _, err = io.Copy(headerWriter, f) return err } } func Unzip(zipPath, dstDir string, cb func(per1000 int)) error { // open zip file reader, err := zip.OpenReader(zipPath) if err != nil { return err } defer reader.Close() total := len(reader.File) for index, file := range reader.File { per1000 := int(float32(index+1) / float32(total) * 1000) // log.Println("unzip=>", file.Name, index, "/", len(reader.File)) log.Println("unzip=>", file.Name) if cb != nil { cb(per1000) } if err := unzipFile(file, dstDir); err != nil { return err } } return nil } func unzipFile(file *zip.File, dstDir string) error { // create the directory of file filePath := path.Join(dstDir, file.Name) if file.FileInfo().IsDir() { if err := os.MkdirAll(filePath, os.ModePerm); err != nil { return err } return nil } if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { return err } // open the file rc, err := file.Open() if err != nil { return err } defer rc.Close() // create the file w, err := os.Create(filePath) if err != nil { return err } defer w.Close() // save the decompressed file content _, err = io.Copy(w, rc) return err }