为了账号安全,请及时绑定邮箱和手机立即绑定

Go中高效读写CSV

Go中高效读写CSV

Go
万千封印 2021-11-01 15:19:37
下面的 Go 代码读取 10,000 条记录的 CSV(时间戳times和浮点数values),对数据运行一些操作,然后将原始值连同score. 然而,它非常慢(即几个小时,但大部分时间是calculateStuff()),我很好奇我可以处理的 CSV 读/写是否有任何低效。package mainimport (  "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方法。
查看完整描述

3 回答

?
Cats萌萌

TA贡献1805条经验 获得超9个赞

您首先将文件加载到内存中,然后对其进行处理,这对于大文件来说可能会很慢。


您需要一次循环调用.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

}



查看完整回答
反对 回复 2021-11-01
?
小唯快跑啊

TA贡献1863条经验 获得超2个赞

package main


import (

  "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(),最好是把它分成几个函数,但这超出了这个问题的范围。


查看完整回答
反对 回复 2021-11-01
  • 3 回答
  • 0 关注
  • 194 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信