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函数中。
发表评论