Go 处理zip压缩文件

压缩ZIP

通过该方法你可以将目录或文件压缩到可写IO中,例如文件、内存......

// Zip 压缩文件或目录
// @params dst io.Writer 压缩文件可写流
// @params src string    待压缩源文件/目录路径
func Zip(dst io.Writer, src string) error {
	// 强转一下路径
	src = filepath.Clean(src)
	// 提取最后一个文件或目录的名称
	baseFile := filepath.Base(src)
	// 判断src是否存在
	_, err := os.Stat(src)
	if err != nil {
		return err
	}

	// 通文件流句柄创建一个ZIP压缩包
	zw := zip.NewWriter(dst)
	// 延迟关闭这个压缩包
	defer zw.Close()

	// 通过filepath封装的Walk来递归处理源路径到压缩文件中
	return filepath.Walk(src, func(path string, info fs.FileInfo, err error) error {
		// 是否存在异常
		if err != nil {
			return err
		}

		// 通过原始文件头信息,创建zip文件头信息
		zfh, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}

        // 赋值默认的压缩方法,否则不压缩
        zfh.Method = zip.Deflate

		// 移除绝对路径
		tmpPath := path
		index := strings.Index(tmpPath, baseFile)
		if index > -1 {
			tmpPath = tmpPath[index:]
		}
		// 替换文件名,并且去除前后 "\" 或 "/"
		tmpPath = strings.Trim(tmpPath, string(filepath.Separator))
		// 替换一下分隔符,zip不支持 "\\"
		zfh.Name = strings.ReplaceAll(tmpPath, "\\", "/")
		// 目录需要拼上一个 "/" ,否则会出现一个和目录一样的文件在压缩包中
		if info.IsDir() {
			zfh.Name += "/"
		}

		// 写入文件头信息,并返回一个ZIP文件写入句柄
		zfw, err := zw.CreateHeader(zfh)
		if err != nil {
			return err
		}

		// 仅在他是标准文件时进行文件内容写入
		if zfh.Mode().IsRegular() {
			// 打开要压缩的文件
			sfr, err := os.Open(path)
			if err != nil {
				return err
			}
			defer sfr.Close()

			// 将srcFileReader拷贝到zipFilWrite中
			_, err = io.Copy(zfw, sfr)
			if err != nil {
				return err
			}
		}

		// 搞定
		return nil
	})
}

解压ZIP

通过该方法你可以将ZIP压缩流解压到指定目录

// Unzip 解压压缩文件
// @params dst string      解压后的目标路径
// @params src *zip.Reader 压缩文件可读流
func Unzip(dst string, src *zip.Reader) error {
	// 强制转换一遍目录
	dst = filepath.Clean(dst)

	// 遍历压缩文件
	for _, file := range src.File {
		// 在闭包中完成以下操作可以及时释放文件句柄
		err := func() error {
			// 跳过文件夹
			if file.Mode().IsDir() {
				return nil
			}

			// 配置输出目标路径
			filename := filepath.Join(dst, file.Name)
			// 创建目标路径所在文件夹
			e := os.MkdirAll(filepath.Dir(filename), os.ModeDir)
			if e != nil {
				return e
			}

			// 打开这个压缩文件
			zfr, e := file.Open()
			if e != nil {
				return e
			}
			defer zfr.Close()

			// 创建目标文件
			fw, e := os.Create(filename)
			if e != nil {
				return e
			}
			defer fw.Close()

			// 执行拷贝
			_, e = io.Copy(fw, zfr)
			if e != nil {
				return e
			}

			// 拷贝成功
			return nil
		}()

		// 是否发生异常
		if err != nil {
			return err
		}
	}

	// 解压完成
	return nil
}

对压缩二次封装

// ZipToFile 压缩至文件
// @params dst string 压缩文件目标路径
// @params src string 待压缩源文件/目录路径
// @return     error  错误信息
func ZipToFile(dst, src string) error {
	// 创建一个ZIP文件
	fw, err := os.Create(filepath.Clean(dst))
	if err != nil {
		return err
	}
	defer fw.Close()

	// 执行压缩
	return Zip(fw, src)
}

// ZipToBytes 压缩至字节流
// @params src string 待压缩源文件/目录路径
// @return []byte 压缩字节流
// @return error  错误信息
func ZipToBytes(src string) ([]byte, error) {
	// 创建一个缓冲区
	buf := bytes.NewBuffer(nil)

	// 执行压缩
	err := Zip(buf, src)
	if err != nil {
		return nil, err
	}

	// 返回缓冲区的二进制流
	return buf.Bytes(), nil
}

对解压二次封装

// UnzipFromFile 解压压缩文件
// @params dst string 解压后目标路径
// @params src string 压缩文件目标路径
func UnzipFromFile(dst, src string) error {
	// 打开压缩文件
	zr, err := zip.OpenReader(filepath.Clean(src))
	if err != nil {
		return err
	}
	defer zr.Close()

	// 解压
	return Unzip(dst, &zr.Reader)
}

// UnzipFromBytes 解压压缩字节流
// @params dst string 解压后目标路径
// @params src []byte 压缩字节流
func UnzipFromBytes(dst string, src []byte) error {
	// 通过字节流创建zip的Reader对象
	zr, err := zip.NewReader(bytes.NewReader(src), int64(len(src)))
	if err != nil {
		return err
	}

	// 解压
	return Unzip(dst, zr)
}

测试一下

func main() {
	// 压缩目录到指定路径
	err := ZipToFile("../build.zip", "../build")
	if err != nil {
		log.Fatalln(err.Error())
	}

	// 解压文件
	err = UnzipFromFile("../build_dst_1", "../build.zip")
	if err != nil {
		log.Fatalln(err.Error())
	}

	// 压缩目录到字节流
	buf, err := ZipToBytes("../build")
	if err != nil {
		log.Fatalln(err.Error())
	}

	// 解压字节流
	err = UnzipFromBytes("../build_dst_2", buf)
	if err != nil {
		log.Fatalln(err.Error())
	}
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Golang中,可以使用`archive/zip`包来进行zip压缩。下面是一个简单的示例代码,演示如何使用该包进行文件或目录的压缩: ```go package main import ( "archive/zip" "fmt" "io" "os" "path/filepath" ) func main() { // 要压缩文件或目录路径 source := "/path/to/source" // 压缩后的zip文件路径 destination := "/path/to/destination.zip" err := zipFiles(destination, source) if err != nil { fmt.Println(err) } else { fmt.Println("压缩完成!") } } func zipFiles(destination string, source string) error { // 创建一个新的zip文件 zipFile, err := os.Create(destination) if err != nil { return err } defer zipFile.Close() // 创建zip.Writer,用于向zip文件中写入数据 archive := zip.NewWriter(zipFile) defer archive.Close() // 递归遍历源路径下的所有文件和目录 filepath.Walk(source, func(path string, info os.FileInfo, err error) error { if err != nil { return err } // 获取源路径下的相对路径,用于在zip文件中创建相应的目录结构 relativePath, err := filepath.Rel(source, path) if err != nil { return err } // 创建一个新的文件或目录头部 header, err := zip.FileInfoHeader(info) if err != nil { return err } // 设置头部的名称为相对路径 header.Name = relativePath if info.IsDir() { // 如果是目录,则写入一个目录头部到zip文件中 header.Name += "/" header.Method = zip.Store } else { // 如果是文件,则写入文件内容到zip文件中 header.Method = zip.Deflate } // 创建一个新的文件或目录条目,写入zip.Writer中 writer, err := archive.CreateHeader(header) if err != nil { return err } if !info.IsDir() { // 如果是文件,则打开源文件并将内容复制到zip文件中 file, err := os.Open(path) if err != nil { return err } defer file.Close() _, err = io.Copy(writer, file) if err != nil { return err } } return nil }) return nil } ``` 你可以将`source`和`destination`变量替换为你希望的路径,然后运行代码即可实现压缩。请确保你拥有对源文件或目录的读取权限,并且目标路径是一个有效的zip文件路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值