前言

碰到了需要golang进行压缩文件夹的操作,在网上搜索到的压缩代码大多都一样,如下所示

// Zip 打包成zip文件
func Zip(filesDir string, zipPath string) {

    // 预防:旧文件无法覆盖
    os.RemoveAll(zipPath)

    // 创建:zip文件
    zipfile, _ := os.Create(zipPath)
    defer zipfile.Close()

    // 打开:zip文件
    archive := zip.NewWriter(zipfile)
    defer archive.Close()

    // 遍历路径信息
    filepath.Walk(filesDir, func(path string, info os.FileInfo, _ error) error {
        // 如果是源路径,提前进行下一个遍历
        if path == filesDir {
            return nil
        }

        // 获取:文件头信息
        header, _ := zip.FileInfoHeader(info)
        header.Name = strings.TrimPrefix(path, filesDir+`\`)

        // 判断:文件是不是文件夹
        if info.IsDir() {
            header.Name += `/`
        } else {
            // 设置:zip的文件压缩算法
            header.Method = zip.Deflate
        }
        // 创建:压缩包头部信息
        writer, _ := archive.CreateHeader(header)
        if !info.IsDir() {
            file, _ := os.Open(path)
            defer file.Close()
            io.Copy(writer, file)
        }
        return nil
    })
}

运行后发现,他会将源文件的路径带入到压缩包内,并创建很多层路径文件夹,排查代码后发现,问题出在第24行

header.Name = strings.TrimPrefix(path, filesDir+`\`)

压缩代码

这一行的作用是将源文件的路径去掉前面压缩路径的部分,但是他用的符号是"\",而linux下的文件路径符号是"/",也就是该代码仅适用于win平台,进行改良后,能兼容win,linux双平台下的代码如下

// Zip 打包成zip文件
func Zip(filesDir string, zipPath string) {
    sysType := runtime.GOOS
    if sysType == "windows" {
        // windows系统   统一路径符号为"\"
        filesDir = strings.ReplaceAll(filesDir, "/", "\\")
    }
    // 预防:旧文件无法覆盖
    os.RemoveAll(zipPath)

    // 创建:zip文件
    zipfile, _ := os.Create(zipPath)
    defer zipfile.Close()

    // 打开:zip文件
    archive := zip.NewWriter(zipfile)
    defer archive.Close()

    // 遍历路径信息
    filepath.Walk(filesDir, func(path string, info os.FileInfo, _ error) error {
        // 如果是源路径,提前进行下一个遍历
        if path == filesDir {
            return nil
        }

        // 获取:文件头信息
        header, _ := zip.FileInfoHeader(info)
        if sysType == "windows" {
            header.Name = strings.TrimPrefix(path, filesDir+`\`)
        } else {
            header.Name = strings.TrimPrefix(path, filesDir+`/`)
        }

        // 判断:文件是不是文件夹
        if info.IsDir() {
            header.Name += `/`
        } else {
            // 设置:zip的文件压缩算法
            header.Method = zip.Deflate
        }
        // 创建:压缩包头部信息
        writer, _ := archive.CreateHeader(header)
        if !info.IsDir() {
            file, _ := os.Open(path)
            defer file.Close()
            io.Copy(writer, file)
        }
        return nil
    })
}

解压代码

另外附上解压文件的代码

// Unzip 解压文件
func Unzip(zipPath, dstDir string) error {
// 打开压缩包
reader, err := zip.OpenReader(zipPath)
if err != nil {
return err
}
defer reader.Close()
for _, file := range reader.File {
if err := unzipFile(file, dstDir); err != nil {
return err
}
}
return nil
}

func unzipFile(file *zip.File, dstDir string) error {
// 创建文件目录
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
}

// 读取文件内容
rc, err := file.Open()
if err != nil {
return err
}
defer rc.Close()

// 创建空文件
w, err := os.Create(filePath)
if err != nil {
return err
}
defer w.Close()

// 保存文件内容
_, err = io.Copy(w, rc)
return err

}
最后修改:2023 年 06 月 02 日
如果觉得我的文章对你有用,请随意打赏