go语言拆分特大大CSV文件

作者 2024年08月30日 21:16 阅读 173

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函数中。

 

 

 

 

发表评论