TypechoJoeTheme

至尊技术网

登录
用户名
密码

Golang如何做一个文件压缩解压工具:Golangzip包操作项目实践

2025-11-21
/
0 评论
/
2 阅读
/
正在检测是否收录...
11/21

本文通过实际项目示例,详细介绍如何使用 Golang 的 archive/zip 包实现文件的压缩与解压功能,涵盖目录遍历、文件写入 ZIP 归档、读取并提取压缩包内容等核心操作,帮助开发者快速构建轻量级跨平台压缩工具。


在日常开发中,我们经常需要处理文件归档和传输问题。无论是服务端日志打包、用户上传资源整理,还是配置文件分发,压缩与解压都是不可或缺的功能模块。Golang 以其简洁高效的特性,在构建这类工具时表现出色。借助标准库中的 archive/zip 包,我们可以轻松实现一个功能完整、性能可靠的 ZIP 压缩解压工具。

要开始这个项目,首先需要理解 Go 标准库对 ZIP 文件的支持机制。archive/zip 提供了读写 ZIP 格式文件的能力,无需引入第三方依赖,非常适合构建轻量级命令行工具或嵌入到服务中作为辅助功能。

我们先从压缩功能入手。目标是将指定目录下的所有文件(包括子目录)递归打包成一个 ZIP 文件。实现这一功能的关键在于遍历目录结构,并将每个文件以相对路径的形式写入 ZIP 归档。

go
package main

import (
"archive/zip"
"io"
"os"
"path/filepath"
)

func compress(src, dst string) error {
outFile, err := os.Create(dst)
if err != nil {
return err
}
defer outFile.Close()

zipWriter := zip.NewWriter(outFile)
defer zipWriter.Close()

return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
    if err != nil {
        return err
    }

    // 获取相对于源目录的路径
    relPath, err := filepath.Rel(src, path)
    if err != nil {
        return err
    }

    // 创建 ZIP 中的文件头
    header, err := zip.FileInfoHeader(info, "")
    if err != nil {
        return err
    }
    header.Name = filepath.ToSlash(relPath) // 使用正斜杠兼容跨平台

    if info.IsDir() {
        header.Name += "/" // 目录需以 / 结尾
    } else {
        header.Method = zip.Deflate // 使用 DEFLATE 压缩算法
    }

    writer, err := zipWriter.CreateHeader(header)
    if err != nil {
        return err
    }

    if !info.IsDir() {
        file, err := os.Open(path)
        if err != nil {
            return err
        }
        defer file.Close()
        _, err = io.Copy(writer, file)
        return err
    }
    return nil
})

}

上述代码中,我们使用 filepath.Walk 遍历源目录,为每个文件创建对应的 zip.FileHeader,并通过 zip.Writer.CreateHeader 写入数据。特别注意的是,目录路径必须以 / 结尾,且使用 filepath.ToSlash 确保路径分隔符统一为 /,这是 ZIP 格式的规范要求。

接下来实现解压功能。我们需要读取 ZIP 文件,逐个提取其中的条目,并还原到指定目录。

go
func decompress(zipPath, dest string) error {
reader, err := zip.OpenReader(zipPath)
if err != nil {
return err
}
defer reader.Close()

for _, file := range reader.File {
    filePath := filepath.Join(dest, file.Name)

    // 安全检查:防止路径穿越攻击
    if !isValidRelPath(file.Name) {
        continue
    }

    if file.FileInfo().IsDir() {
        os.MkdirAll(filePath, os.ModePerm)
        continue
    }

    // 确保父目录存在
    if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
        return err
    }

    inFile, err := file.Open()
    if err != nil {
        return err
    }

    outFile, err := os.Create(filePath)
    if err != nil {
        inFile.Close()
        return err
    }

    _, err = io.Copy(outFile, inFile)
    outFile.Close()
    inFile.Close()

    if err != nil {
        return err
    }

    // 保留原始文件权限(Unix系统)
    os.Chmod(filePath, file.Mode())
}
return nil

}

// 简单路径校验,防止 ../ 路径穿越
func isValidRelPath(p string) bool {
if strings.Contains(p, "..") || strings.Contains(p, "\") {
return false
}
return true
}

在解压过程中,安全尤为重要。我们加入了路径合法性校验,避免恶意压缩包通过 ../ 实现目录穿越,造成文件覆盖风险。同时,通过 file.Mode() 恢复原始权限,提升工具的专业性。

最后,可以封装一个简单的 CLI 接口,接收命令行参数执行对应操作。例如:

go
func main() {
if len(os.Args) < 4 {
log.Fatal("用法: program [compress|decompress] src dest")
}

mode := os.Args[1]
src := os.Args[2]
dest := os.Args[3]

switch mode {
case "compress":
    if err := compress(src, dest); err != nil {
        log.Fatal(err)
    }
case "decompress":
    if err := decompress(src, dest); err != nil {
        log.Fatal(err)
    }
default:
    log.Fatal("不支持的操作模式")
}

}

这样一个完整的、可运行的压缩解压工具就完成了。它不依赖外部库,具备良好的可移植性,适用于自动化脚本、服务端文件处理等多种场景。通过深入理解 archive/zip 的使用方式,我们不仅能完成基础功能,还能在此基础上扩展加密、分卷、进度反馈等高级特性。

Go语言文件打包zip压缩archive/zip解压工具Golang实战
朗读
赞(0)
版权属于:

至尊技术网

本文链接:

https://www.zzwws.cn/archives/38988/(转载时请注明本文出处及文章链接)

评论 (0)