Go中高效读写CSV

下面的 Go 代码读取 10,000 条记录的 CSV(时间戳times和浮点数values),对数据运行一些操作,然后将原始值连同score. 然而,它非常慢(即几个小时,但大部分时间是calculateStuff()),我很好奇我可以处理的 CSV 读/写是否有任何低效。


package main


import (

  "encoding/csv"

  "log"

  "os"

  "strconv"

)


func ReadCSV(filepath string) ([][]string, error) {

  csvfile, err := os.Open(filepath)


  if err != nil {

    return nil, err

  }

  defer csvfile.Close()


  reader := csv.NewReader(csvfile)

  fields, err := reader.ReadAll()


  return fields, nil

}


func main() {

  // load data csv

  records, err := ReadCSV("./path/to/datafile.csv")

  if err != nil {

    log.Fatal(err)

  }


  // write results to a new csv

  outfile, err := os.Create("./where/to/write/resultsfile.csv"))

  if err != nil {

    log.Fatal("Unable to open output")

  }

  defer outfile.Close()

  writer := csv.NewWriter(outfile)


  for i, record := range records {

    time := record[0]

    value := record[1]


    // skip header row

    if i == 0 {

      writer.Write([]string{time, value, "score"})

      continue

    }


    // get float values

    floatValue, err := strconv.ParseFloat(value, 64)

    if err != nil {

      log.Fatal("Record: %v, Error: %v", floatValue, err)

    }


    // calculate scores; THIS EXTERNAL METHOD CANNOT BE CHANGED

    score := calculateStuff(floatValue)


    valueString := strconv.FormatFloat(floatValue, 'f', 8, 64)

    scoreString := strconv.FormatFloat(prob, 'f', 8, 64)

    //fmt.Printf("Result: %v\n", []string{time, valueString, scoreString})


    writer.Write([]string{time, valueString, scoreString})

  }


  writer.Flush()

}

我正在寻求帮助以尽可能快地制作此 CSV 读/写模板代码。对于这个问题的范围,我们不必担心calculateStuff方法。


万千封印
浏览 195回答 3
3回答

Cats萌萌

您首先将文件加载到内存中,然后对其进行处理,这对于大文件来说可能会很慢。您需要一次循环调用.Read和处理一行。func processCSV(rc io.Reader) (ch chan []string) {    ch = make(chan []string, 10)    go func() {        r := csv.NewReader(rc)        if _, err := r.Read(); err != nil { //read header            log.Fatal(err)        }        defer close(ch)        for {            rec, err := r.Read()            if err != nil {                if err == io.EOF {                    break                }                log.Fatal(err)            }            ch <- rec        }    }()    return}

小唯快跑啊

package mainimport (  "encoding/csv"  "log"  "os"  "strconv")func main() {  // setup reader  csvIn, err := os.Open("./path/to/datafile.csv")  if err != nil {    log.Fatal(err)  }  r := csv.NewReader(csvIn)  // setup writer  csvOut, err := os.Create("./where/to/write/resultsfile.csv"))  if err != nil {    log.Fatal("Unable to open output")  }  w := csv.NewWriter(csvOut)  defer csvOut.Close()  // handle header  rec, err := r.Read()  if err != nil {    log.Fatal(err)  }  rec = append(rec, "score")  if err = w.Write(rec); err != nil {    log.Fatal(err)  }  for {    rec, err = r.Read()    if err != nil {      if err == io.EOF {        break      }      log.Fatal(err)    }    // get float value    value := rec[1]    floatValue, err := strconv.ParseFloat(value, 64)    if err != nil {      log.Fatal("Record, error: %v, %v", value, err)    }    // calculate scores; THIS EXTERNAL METHOD CANNOT BE CHANGED    score := calculateStuff(floatValue)    scoreString := strconv.FormatFloat(score, 'f', 8, 64)    rec = append(rec, scoreString)    if err = w.Write(rec); err != nil {      log.Fatal(err)    }  w.Flush()  }}注意当然逻辑都被塞进了main(),最好是把它分成几个函数,但这超出了这个问题的范围。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go