Go压缩≥60MB JSON文件至tar.gz时数据丢失问题解决
问题分析与解决方案
你的代码在处理大文件时出现数据截断,主要是因为手动文件读写循环存在潜在的边界处理问题,同时路径生成方式不够可靠。以下是修复后的代码及关键修改说明:
修复后的代码
func CreateTarGz(sourceDir, targetFile string) error { target, err := os.Create(targetFile) if err != nil { return err } defer target.Close() gw := gzip.NewWriter(target) defer gw.Close() tw := tar.NewWriter(gw) defer tw.Close() return filepath.Walk(sourceDir, func(path string, info fs.FileInfo, err error) error { if err != nil { return err } // 生成tar文件头 header, err := tar.FileInfoHeader(info, "") if err != nil { return err } // 用filepath.Rel生成可靠的相对路径,替代两次TrimPrefix relPath, err := filepath.Rel(sourceDir, path) if err != nil { return err } header.Name = relPath if err := tw.WriteHeader(header); err != nil { return err } if info.IsDir() { return nil } // 打开源文件 file, err := os.Open(path) if err != nil { return err } defer file.Close() // 使用io.Copy替代手动循环,自动处理所有读写逻辑 if _, err := io.Copy(tw, file); err != nil { log.Printf("failed to copy file %s to tar: %v", path, err) return err } return nil }) }
关键修改点说明
- 替换手动读写循环为
io.Copy:io.Copy是标准库提供的可靠工具,会自动处理缓冲区管理、EOF判断和错误处理,避免手动循环中可能出现的边界遗漏,这是解决大文件数据截断的核心修复。 - 用
filepath.Rel生成相对路径:原代码的两次TrimPrefix在跨平台场景或复杂路径下可能出错,filepath.Rel会根据系统路径规则正确计算相对于源目录的路径,确保tar包内的文件结构正确。 - 移除多余的
header.Size设置:tar.FileInfoHeader已经会根据文件信息自动设置header.Size,手动重复设置属于冗余操作,且无实际作用。 - 调整函数返回逻辑:将
filepath.Walk的直接返回简化,让代码结构更清晰。
额外注意事项
- 确保所有defer的关闭顺序正确:
tar.Writer先关闭,再关闭gzip.Writer,最后关闭目标文件,原代码的defer顺序已经符合要求,无需调整。 - 如果需要调整压缩级别,可以在创建
gzip.Writer时使用gzip.NewWriterLevel指定,例如gzip.NewWriterLevel(target, gzip.BestSpeed)来提升大文件压缩速度。
内容的提问来源于stack exchange,提问作者tuan.1203
相关产品推荐
相关产品推荐

