github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/compress/zip.go (about) 1 package compress 2 3 import ( 4 "archive/zip" 5 "io" 6 "io/fs" 7 "os" 8 "path" 9 "path/filepath" 10 "strings" 11 ) 12 13 //// Compress 压缩文件 14 15 func Zip(zipPath string, paths []string) error { 16 // create zip file 17 if err := os.MkdirAll(filepath.Dir(zipPath), os.ModePerm); err != nil { 18 return err 19 } 20 archive, err := os.Create(zipPath) 21 if err != nil { 22 return err 23 } 24 defer func(archive *os.File) { 25 _ = archive.Close() 26 }(archive) 27 28 // new zip writer 29 zipWriter := zip.NewWriter(archive) 30 defer func(zipWriter *zip.Writer) { 31 _ = zipWriter.Close() 32 }(zipWriter) 33 34 // traverse the file or directory 35 for _, srcPath := range paths { 36 // remove the trailing path separator if path is a directory 37 srcPath = strings.TrimSuffix(srcPath, string(os.PathSeparator)) 38 39 // visit all the files or directories in the tree 40 err = filepath.Walk(srcPath, func(path string, info fs.FileInfo, err error) error { 41 if err != nil { 42 return err 43 } 44 45 // create a local file header 46 header, err := zip.FileInfoHeader(info) 47 if err != nil { 48 return err 49 } 50 51 // set compression 52 header.Method = zip.Deflate 53 54 // set relative path of a file as the header name 55 header.Name, err = filepath.Rel(filepath.Dir(srcPath), path) 56 if err != nil { 57 return err 58 } 59 if info.IsDir() { 60 header.Name += string(os.PathSeparator) 61 } 62 63 // create writer for the file header and save content of the file 64 headerWriter, err := zipWriter.CreateHeader(header) 65 if err != nil { 66 return err 67 } 68 if info.IsDir() { 69 return nil 70 } 71 err = copyFile(path, headerWriter) 72 if err != nil { 73 return err 74 } 75 return err 76 }) 77 if err != nil { 78 return err 79 } 80 } 81 return nil 82 } 83 84 func copyFile(fileSrcPath string, dstWriter io.Writer) error { 85 f, err := os.Open(fileSrcPath) 86 if err != nil { 87 return err 88 } 89 defer func(f *os.File) { 90 _ = f.Close() 91 }(f) 92 _, err = io.Copy(dstWriter, f) 93 return err 94 } 95 96 // Unzip decompresses a zip file to specified directory. 97 // Note that the destination directory don't need to specify the trailing path separator. 98 func Unzip(zipPath, dstDir string) error { 99 // open zip file 100 reader, err := zip.OpenReader(zipPath) 101 if err != nil { 102 return err 103 } 104 defer func(reader *zip.ReadCloser) { 105 _ = reader.Close() 106 }(reader) 107 for _, file := range reader.File { 108 if err := unzipFile(file, dstDir); err != nil { 109 return err 110 } 111 } 112 return nil 113 } 114 115 func unzipFile(file *zip.File, dstDir string) error { 116 // create the directory of file 117 filePath := path.Join(dstDir, file.Name) 118 if file.FileInfo().IsDir() { 119 if err := os.MkdirAll(filePath, os.ModePerm); err != nil { 120 return err 121 } 122 return nil 123 } 124 if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { 125 return err 126 } 127 128 // open the file 129 rc, err := file.Open() 130 if err != nil { 131 return err 132 } 133 defer func(rc io.ReadCloser) { 134 _ = rc.Close() 135 }(rc) 136 137 // create the file 138 w, err := os.Create(filePath) 139 if err != nil { 140 return err 141 } 142 defer func(w *os.File) { 143 _ = w.Close() 144 }(w) 145 146 // save the decompressed file content 147 _, err = io.Copy(w, rc) 148 return err 149 }