导读:本期聚焦于小伙伴创作的《如何用Golang实现文件压缩与解压?完整代码示例与实战教程》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何用Golang实现文件压缩与解压?完整代码示例与实战教程》有用,将其分享出去将是对创作者最好的鼓励。

Golang实现文件压缩与解压功能

在实际业务开发中,文件压缩和解压是经常会用到的功能,比如日志归档、批量文件传输等场景。Golang标准库中已经提供了完善的压缩相关支持,我们可以利用archive/zip包快速实现文件的压缩与解压逻辑,无需依赖第三方库。本文将详细介绍两种功能的实现方式,并附上完整可运行的代码示例。

一、文件压缩功能实现

文件压缩的核心思路是:创建zip压缩文件,遍历需要压缩的源文件/目录,将每个文件的内容写入zip文件的对应条目中。需要注意处理目录的递归遍历,以及文件权限的保留。

下面是完整的文件压缩实现代码:

package main

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

// Compress 压缩文件或目录到指定的zip文件
// srcPath 是要压缩的源文件或目录路径
// destZipPath 是生成的zip文件路径
func Compress(srcPath string, destZipPath string) error {
	// 创建目标zip文件
	zipFile, err := os.Create(destZipPath)
	if err != nil {
		return fmt.Errorf("创建zip文件失败: %v", err)
	}
	defer zipFile.Close()

	// 创建zip写入器
	zipWriter := zip.NewWriter(zipFile)
	defer zipWriter.Close()

	// 获取源路径的绝对路径,避免相对路径导致的条目路径错误
	absSrcPath, err := filepath.Abs(srcPath)
	if err != nil {
		return fmt.Errorf("获取源路径绝对路径失败: %v", err)
	}

	// 获取源路径的根目录名,用于拼接zip内的条目路径
	baseName := filepath.Base(absSrcPath)

	// 定义遍历处理的回调函数
	var walkFunc filepath.WalkFunc = func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return fmt.Errorf("遍历路径失败 %s: %v", path, err)
		}
		// 如果是目录,只创建目录条目(如果是根目录则跳过创建空条目)
		if info.IsDir() {
			// 根目录不需要单独创建条目
			if path == absSrcPath {
				return nil
			}
			// 计算zip内的条目路径
			relPath, err := filepath.Rel(absSrcPath, path)
			if err != nil {
				return err
			}
			entryPath := filepath.Join(baseName, relPath) + "/"
			// 创建目录条目
			_, err = zipWriter.Create(entryPath)
			return err
		}
		// 是文件,打开文件准备写入zip
		file, err := os.Open(path)
		if err != nil {
			return fmt.Errorf("打开文件失败 %s: %v", path, err)
		}
		defer file.Close()

		// 计算zip内的条目路径
		relPath, err := filepath.Rel(absSrcPath, path)
		if err != nil {
			return err
		}
		entryPath := filepath.Join(baseName, relPath)
		// 创建zip条目
		writer, err := zipWriter.Create(entryPath)
		if err != nil {
			return fmt.Errorf("创建zip条目失败: %v", err)
		}
		// 拷贝文件内容到zip条目
		_, err = io.Copy(writer, file)
		return err
	}

	// 开始遍历源路径
	err = filepath.Walk(absSrcPath, walkFunc)
	if err != nil {
		return fmt.Errorf("压缩过程出错: %v", err)
	}

	fmt.Printf("压缩完成,生成文件: %s\n", destZipPath)
	return nil
}

func main() {
	// 示例:压缩当前目录下的test_dir目录,生成test.zip
	err := Compress("./test_dir", "./test.zip")
	if err != nil {
		fmt.Printf("压缩失败: %v\n", err)
	}
}

上述代码中,Compress函数接收源路径和目标zip路径两个参数,通过filepath.Walk递归遍历源路径下的所有文件和目录,为每个文件创建对应的zip条目并写入内容,目录则创建对应的目录条目。如果源路径是单个文件,同样可以正常处理,因为filepath.Walk对于单个文件只会遍历一次。

二、文件解压功能实现

文件解压的核心思路是:打开zip文件,遍历其中的所有条目,根据条目类型(文件/目录)创建对应的本地文件或目录,并将文件条目的内容写入本地文件。

下面是完整的解压实现代码:

package main

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

// Decompress 解压zip文件到指定目录
// zipPath 是要解压的zip文件路径
// destDir 是解压目标目录路径
func Decompress(zipPath string, destDir string) error {
	// 打开zip文件
	zipReader, err := zip.OpenReader(zipPath)
	if err != nil {
		return fmt.Errorf("打开zip文件失败: %v", err)
	}
	defer zipReader.Close()

	// 遍历zip中的所有条目
	for _, file := range zipReader.File {
		// 拼接目标路径,避免路径穿越攻击
		// 例如zip条目路径为../../etc/passwd的情况,需要过滤
		targetPath := filepath.Join(destDir, file.Name)
		// 再次校验目标路径是否在destDir下
		absDestDir, err := filepath.Abs(destDir)
		if err != nil {
			return err
		}
		absTargetPath, err := filepath.Abs(targetPath)
		if err != nil {
			return err
		}
		if !strings.HasPrefix(absTargetPath, absDestDir) {
			return fmt.Errorf("非法的zip条目路径: %s", file.Name)
		}

		// 如果是目录,创建目录
		if file.FileInfo().IsDir() {
			err := os.MkdirAll(targetPath, os.ModePerm)
			if err != nil {
				return fmt.Errorf("创建目录失败 %s: %v", targetPath, err)
			}
			continue
		}

		// 是文件,先确保父目录存在
		if err := os.MkdirAll(filepath.Dir(targetPath), os.ModePerm); err != nil {
			return fmt.Errorf("创建父目录失败: %v", err)
		}

		// 创建目标文件
		outFile, err := os.OpenFile(targetPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
		if err != nil {
			return fmt.Errorf("创建目标文件失败 %s: %v", targetPath, err)
		}

		// 打开zip中的文件条目
		rc, err := file.Open()
		if err != nil {
			outFile.Close()
			return fmt.Errorf("打开zip条目失败: %v", err)
		}

		// 拷贝内容到目标文件
		_, err = io.Copy(outFile, rc)
		// 先关闭所有打开的资源,再处理错误
		rc.Close()
		outFile.Close()
		if err != nil {
			return fmt.Errorf("写入文件内容失败 %s: %v", targetPath, err)
		}
	}

	fmt.Printf("解压完成,文件位于: %s\n", destDir)
	return nil
}

func main() {
	// 示例:解压当前目录下的test.zip到./unzip_dir目录
	err := Decompress("./test.zip", "./unzip_dir")
	if err != nil {
		fmt.Printf("解压失败: %v\n", err)
	}
}

解压函数中特别加入了路径合法性校验,避免zip条目路径包含../等字符导致的路径穿越攻击,这是实际生产环境中必须考虑的安全点。同时,对于文件条目会先创建其父目录,避免因为父目录不存在导致文件创建失败。

三、功能测试与注意事项

测试时可以按照以下步骤验证功能:

  • 先创建测试目录test_dir,在其中放入几个测试文件和子目录,运行压缩程序生成test.zip
  • 删除原test_dir目录,运行解压程序将test.zip解压到unzip_dir,对比解压后的文件和原文件是否一致

需要注意的几点:

  • 压缩时如果源路径是绝对路径,zip内的条目路径会保留完整的目录结构,建议根据需求调整条目路径的拼接逻辑
  • 大文件压缩解压时可以添加进度回调,提升用户体验
  • 如果需要支持其他压缩格式(如tar.gz),可以使用compress/gziparchive/tar包,实现思路类似

Golang文件压缩文件解压archive_zipGo语言教程 本作品最后修改时间:2026-05-23 10:46:11

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。