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

如何使用Golang将大文件等分为4个文件且保证数据顺序不变

问题根因

  • 原有实现将所有读取到的行全部写入同一个公共通道,4个工作协程是随机竞争消费通道内的行数据,没有任何顺序保证,最终分块的内容自然会乱序
  • 原有逻辑是按行数近似拆分,无法保证每个分块大小固定为25MB

优化实现

下面的实现既可以保证分块内数据顺序和原文件一致,也能严格按照你要求的25MB大小拆分,且不会把单行内容切分到两个分块中:

package main

import (
	"bufio"
	"log"
	"os"
	"sync"

	"github.com/google/uuid"
)

const chunkSize = 25 * 1024 * 1024 // 单块大小25MB

func main() {
	// 先确保chunks目录存在
	err := os.MkdirAll("chunks", 0755)
	if err != nil {
		log.Fatal("创建chunks目录失败:", err)
	}

	file, err := os.Open("sampletest.txt")
	if err != nil {
		log.Fatal("打开源文件失败:", err)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	var wg sync.WaitGroup
	var currentChunk string
	var currentSize int

	for scanner.Scan() {
		line := scanner.Text() + "\n"
		lineSize := len(line)

		// 加入当前行后超过单块大小,就先写入现有块,再开新块
		if currentSize+lineSize > chunkSize && currentSize > 0 {
			wg.Add(1)
			go writeChunk(currentChunk, &wg)
			currentChunk = ""
			currentSize = 0
		}

		currentChunk += line
		currentSize += lineSize
	}

	// 处理最后不足25MB的剩余内容
	if currentSize > 0 {
		wg.Add(1)
		go writeChunk(currentChunk, &wg)
	}

	if err := scanner.Err(); err != nil {
		log.Fatal("读取源文件失败:", err)
	}

	// 等待所有分块写入完成再退出
	wg.Wait()
}

func writeChunk(data string, wg *sync.WaitGroup) {
	defer wg.Done()
	file, err := os.Create("chunks/" + uuid.New().String() + ".txt")
	if err != nil {
		log.Println("创建分块文件失败:", err)
		return
	}
	defer file.Close()
	_, err = file.WriteString(data)
	if err != nil {
		log.Println("写入分块文件失败:", err)
	}
}

实现说明

  • 按原文件顺序逐行读取,在内存中攒够25MB就异步写入新的分块文件,全局顺序不会乱
  • 单块大小判断时会留足当前行的空间,不会把一行拆到两个分块里
  • 用WaitGroup等待所有分块写入完成再退出程序,不会丢数据
  • 如果你需要严格得到4个分块,哪怕最后一块不足25MB也凑4块,可以调整判断逻辑,固定攒够前3块各25MB,剩下的内容都放第4块即可

小提示:本地文件读取属于IO密集型操作,单协程顺序读取的效率远高于多协程随机读取,上面的实现兼顾了读取效率和写入并发,是处理这类文件拆分场景的最优选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 15:39:03