当前位置: 首页 > article >正文

golang压缩与解压缩文件

全代码实现,如有帮助,欢迎留下足迹。

目录

压缩

核心处理

解压缩


 

压缩

入口压缩函数

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 string
    for _, 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.Writer

    if !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)

    }
}

 

 


http://www.kler.cn/a/232408.html

相关文章:

  • 【算法】二分查找
  • 常用在汽车PKE无钥匙进入系统的高度集成SOC芯片:CSM2433
  • 二叉树遍历的非递归实现和复杂度分析
  • 聊天服务器(9)一对一聊天功能
  • 接口文档的定义
  • 通过Python 调整Excel行高、列宽
  • Sqli靶场23-->30
  • Spring AI - 使用向量数据库实现检索式AI对话
  • Akamai 如何揪出微软 RPC 服务中的漏洞
  • 零基础学Python(9)— 流程控制语句(下)
  • Python爬虫 Beautiful Soup库详解#4
  • JavaScript valueOf() 方法详解
  • Oracle的权限
  • 在工业制造方面,如何更好地实现数字化转型?
  • 蓝桥杯刷题day08——完全日期
  • [力扣 Hot100]Day26 环形链表 II
  • TCP的连接和断开详解
  • 【LeetCode每日一题】525连续数组 303区域和检索(前缀和的基本概念和3个简单案例)
  • 使用Linux docker方式快速安装Plik并结合内网穿透实现公网访问
  • leetcode69 x 的平方根
  • Antd+React+react-resizable实现表格拖拽功能
  • 代码随想录算法训练营DAY16 | 二叉树 (3)
  • 机器学习——有监督学习和无监督学习
  • SQL注入 - 利用报错函数 floor 带回回显
  • flask+vue+python跨区通勤人员健康体检预约管理系统
  • C++ 调用lua 脚本