go 读取大文件时,不要使用os.readFile,会导致内存溢出,应该使用 bufio.NewScanner(f) 逐行读取!并设置一定大小的缓冲区,不然会报错:
Golang解决bufio.Scanner: token too long的问题
在Go语言中使用bufio.Scanner时,遇到“token too long”(标记过长)的错误,通常是因为尝试读取的行太大,超过了bufio.Scanner默认的最大容量。bufio.Scanner默认的缓冲区大小为64KB,如果尝试读取的行大于这个大小,就会报错“token too long”。
buf := make([]byte, 0, 1*1024*1024) // 创建一个初始大小为1M的缓冲区
scanner.Buffer(buf, 10*1024*1024) // 将最大缓冲区大小增加到10MB
代码如下
package main import ( "bufio" "fmt" "github.com/spf13/cast" "log" "os" ) func SpliteCSV() { f, err := os.Open("./data.csv") if err != nil { log.Fatal(err) } defer f.Close() scanner := bufio.NewScanner(f) buf := make([]byte, 0, 1*1024*1024) // 创建一个初始大小为1M的缓冲区 scanner.Buffer(buf, 10*1024*1024) // 将最大缓冲区大小增加到10MB lineCount := 0 currentFile := createNewCsvFile("output-0.csv") defer currentFile.Close() header := "" for scanner.Scan() { txt := scanner.Text() if header == "" { header = txt _, err = currentFile.WriteString(header + "\n") } lineCount++ if lineCount%1000 == 0 { currentFile.Close() // 关闭当前文件 name := "output-" + cast.ToString(lineCount) + ".csv" currentFile = createNewCsvFile(name) currentFile.WriteString(header + "\n") fmt.Println(cast.ToString(lineCount) + "====> 拆分新文件:" + name) } if txt != header { _, err = currentFile.WriteString(txt + "\n") } if err != nil { fmt.Println("XXXXXXXXXXXXXXXXXXXXXXX出错了!!!!", err) panic(err) } } if err := scanner.Err(); err != nil { fmt.Println("XXXXXXXXXXXXXXXXXXXXXXX出错了!!!!", err) log.Fatal(err) } fmt.Println("###############拆分完成!!#########################") } func createNewCsvFile(filename string) *os.File { file, err := os.Create(filename) if err != nil { log.Fatalf("Error creating file: %v", err) } return file } // 注意:在这个简单的示例中,我们没有在write2CSV函数中做太多工作, // 因为我们直接在循环中处理了文件的打开、写入和关闭。 // 如果需要更复杂的逻辑,可以将这些操作封装到write2CSV函数中。
发表评论