You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Go的compress/gzip压缩文件夹文件后解压异常求助

问题分析与解决方案:Go语言压缩多文件后解压异常

问题根源

gzip格式本身仅支持单个文件的压缩,你的代码将两个文件的内容直接依次写入同一个gzip Writer,并且每次覆盖gzipWriter.Name字段。解压工具最终只会识别最后一次设置的文件名,同时把两个文件的内容合并到该文件中,这就是你得到3MB的first.txt的原因。

解决方案

要实现多文件压缩并可完整恢复,需要先将文件打包为tar归档,再对tar包进行gzip压缩(即常见的.tar.gz/.tgz格式)——tar负责将多文件打包成单个归档,gzip负责压缩这个归档文件。

修改后的代码如下:

package services

import (
	"compress/gzip"
	"archive/tar"
	"fmt"
	"io"
	"os"
	"path/filepath"
)

func compress() {
	currentDirectory, _ := os.Getwd()
	sourceFolder := currentDirectory + "/storages"
	outputFilename := currentDirectory + "/storages/output.tar.gz"

	// 创建输出文件
	outputFile, err := os.Create(outputFilename)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer outputFile.Close()

	// 创建gzip压缩写入器
	gzipWriter, err := gzip.NewWriterLevel(outputFile, gzip.BestCompression)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer gzipWriter.Close()

	// 创建tar归档写入器,包裹在gzip写入器外层
	tarWriter := tar.NewWriter(gzipWriter)
	defer tarWriter.Close()

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

		// 跳过目录、gz文件和DS_Store
		if info.IsDir() || filepath.Ext(path) == ".gz" || filepath.Base(path) == ".DS_Store" {
			return nil
		}

		// 打开源文件
		sourceFile, err := os.Open(path)
		if err != nil {
			fmt.Println(err)
			return err
		}
		defer sourceFile.Close()

		// 计算文件相对于源文件夹的路径,保留归档内的文件结构
		relPath, err := filepath.Rel(sourceFolder, path)
		if err != nil {
			fmt.Println(err)
			return err
		}

		// 创建tar头部信息
		header, err := tar.FileInfoHeader(info, "")
		if err != nil {
			fmt.Println(err)
			return err
		}
		// 修正头部的文件名(FileInfoHeader可能会丢失相对路径)
		header.Name = relPath

		// 写入tar头部
		if err := tarWriter.WriteHeader(header); err != nil {
			fmt.Println(err)
			return err
		}

		// 写入文件内容到tar归档
		_, err = io.Copy(tarWriter, sourceFile)
		if err != nil {
			fmt.Println(err)
			return err
		}

		fmt.Printf("已压缩 %s 到 %s\n", path, outputFilename)
		return nil
	})

	if err != nil {
		fmt.Println(err)
	}
}

func main() {
	compress()
}

关键说明

  • 先通过tar.NewWriter创建归档写入器,再用gzip.Writer包裹,实现"打包+压缩"的流程
  • 使用filepath.Rel获取文件相对于源文件夹的路径,确保解压后保留原始文件结构
  • 每个文件对应一个独立的tar.Header,保证解压时能识别为单独的文件

压缩完成后,你会得到output.tar.gz文件,用Keka解压即可恢复原始的两个文件。

内容的提问来源于stack exchange,提问作者lehoangnnx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 18:40:01