全代码实现,如有帮助,欢迎留下足迹。
目录
压缩
核心处理
解压缩
压缩
入口压缩函数
useBasePathInZip参数:
为 false 相当于全文件视图,zip中没有目录
为 true表示保留源文件的路径(srcPaths如果是相对路径,则压缩后zip文件中也是相对路径)
func compress(srcPaths []string, outputPath string, useBasePathInZip bool) {if len(srcPaths) == 0 {return}file, openErr := os.OpenFile(outputPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)if openErr != nil {fmt.Printf("failed to open file %s: %v\n", outputPath, openErr)return}defer file.Close()zipWriter := zip.NewWriter(file)defer zipWriter.Close()for _, path := range srcPaths {info, err := os.Stat(path)if err != nil {fmt.Printf("failed to stat file %s: %v\n", path, err)return}if info.IsDir() {fmt.Printf("%s is dir...\n", path)err = addFilesToDirectory(zipWriter, path, "", useBasePathInZip)if err != nil {return}continue}fmt.Printf("%s is file...\n", path)if err = compressFile(zipWriter, path, useBasePathInZip); err != nil {log.Fatalf("add file %s to zip failed: %s", path, err)}}
}
核心处理
递归压缩目录中的所有文件
func addFilesToDirectory(zw *zip.Writer, newDir, baseInZip string, useBasePathInZip bool) error {files, err := ioutil.ReadDir(newDir)if err != nil {return err}fmt.Printf("目录 %s 下包含 %d 个对象.\n", newDir, len(files))var newBaseInZip stringfor _, fileInfo := range files {if useBasePathInZip {newBaseInZip = filepath.Join(baseInZip, fileInfo.Name())}newFullPath := filepath.Join(newDir, fileInfo.Name())fmt.Printf("\tcheck filename=%s, newFullPath=%s, newBaseInZip=%s \n", fileInfo.Name(), newFullPath, newBaseInZip)// 是目录,递归处理if fileInfo.IsDir() {if err = addFilesToDirectory(zw, newFullPath, newBaseInZip, useBasePathInZip); err != nil {return err}continue}// 处理单个文件if err = compressFile(zw, newFullPath, useBasePathInZip); err != nil {return err}}return nil
}
压缩单个文件
func compressFile(zw *zip.Writer, srcFile string, useBasePathInZip bool) error {fileToZip, err := os.Open(srcFile)if err != nil {log.Fatalf("compressFile failed to open %s: %v", srcFile, err)return err}defer fileToZip.Close()var zipFile io.Writerif !useBasePathInZip {// 获得源文件FileInfo对象info, err := fileToZip.Stat()if err != nil {fmt.Printf("failed to open file %s: %v\n", srcFile, err)return err}// 创建新的ZIP文件头,并设置其内部路径仅为文件名header, err := zip.FileInfoHeader(info)if err != nil {fmt.Printf("failed to create file header for %s: %v\n", srcFile, err)return err}fmt.Println("名称=", header.Name)// 设置压缩后的文件名为源文件名(去掉路径)header.Name = filepath.Base(srcFile)// 基于主zw流创建该文件的目标zip平台zipFile, err = zw.CreateHeader(header)if err != nil {return err}} else {zipFile, err = zw.Create(srcFile)if err != nil {return err}}// 将源文件Copy到目标zip平台_, err = io.Copy(zipFile, fileToZip)fmt.Printf("压缩 %s 完成 %v\n", srcFile, err)return err
}
调用压缩
func main() {var srcPaths = []string{"fzip/zipt/a.txt", "fzip/unzip.go"}compress(srcPaths, "./a.zip", true)
}
解压缩
func unzip(unzipFile, unzipDir string) {zipReader, _ := zip.OpenReader(unzipFile)for i, file := range zipReader.Reader.File {fmt.Printf("正在压缩第 %d 个. name=%s Comment=%s, isDir=%v, size=%d.\n", i+1, file.Name, file.Comment, file.FileInfo().IsDir(), file.FileInfo().Size())func(i int, file *zip.File) {zippedFile, err := file.Open()if err != nil {log.Fatal(err)}defer zippedFile.Close()extractedFilePath := filepath.Join(unzipDir, file.Name)if file.FileInfo().IsDir() {_ = os.MkdirAll(extractedFilePath, file.Mode()) // 权限不变fmt.Println("dir Created:", extractedFilePath)return}fmt.Println("file extracted: ", file.Name)func() {outputFile, err := os.OpenFile(extractedFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())if err != nil {log.Fatal(err)}defer outputFile.Close()_, err = io.Copy(outputFile, zippedFile)if err != nil {log.Fatal(err)}}()}(i, file)}
}