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

从定义的位置重新开始读取 csv 文件

从定义的位置重新开始读取 csv 文件

Go
RISEBY 2022-10-04 15:48:00
我需要在Go中处理一个大文件,所以我不想一次加载我的csv文件的所有行,而是按组处理它们。为了从我离开的位置重新开始计算行,我实际上使用for cycle来跳过已经读取的行:for idx := 0; idx < startAt; idx++ {    //Read rows and do nothing with the returned value    if _, readErr := reader.Read(); readErr != nil {        if readErr == io.EOF {            //File end -> OK            isEOF = true            break        } else {            //Read failed            return nil, errors.New(DATA_READ_ERROR)        }    }}这是一个非常简单的解决方案;但是,它显然是低效的。阅读第一行后,阅读以下内容的时间呈指数级增长。为了减少这一时间,我尝试了不同的替代方案,但每种方法都无法正常工作,并使读取器失败(行不是从正确的地址读取的)。例如,我试图返回文件指针的当前位置(使用,然后在新的迭代中,我试图使用移动指针,但它没有按预期工作。file.Seek(0, io.SeekCurrent)file.Seek(oldPosition, io.SeekStart)有一种方法可以避免上面的循环,并在从我离开的地方重新启动时改善阅读时间?
查看完整描述

1 回答

?
慕桂英546537

TA贡献1848条经验 获得超10个赞

这里的问题是内部使用缓冲读取器,因此当您执行时,您将获得基础文件上的位置,但读取了一些数据并且您没有使用它。encoding/csvfile.Seek(0, io.SeekCurrent)

有两种可能的解决方案:

  • 一种是使用较低级别的实现,允许准确控制您所在的位置

  • 另一个是找出有多少缓冲数据。

我将向您展示第二个选项的实现(请注意,这依赖于对包内部工作的一些了解,如果更改,可能会停止工作)encoding/csv

首先,在创建 csv 之前创建一个新的缓冲 io 读取器:

    //Position the file pointer to the start point

        file.Seek(startAt, io.SeekStart)

        bReader := bufio.NewReader(file)


        //Create a reader

        reader := csv.NewReader(bReader)

这将允许您访问缓冲区。您可以像以前一样使用此读取器,但最终您可以通过以下方式计算文件上的最终位置:

        bufSize := bReader.Buffered()
        filePos, err := file.Seek(0, io.SeekCurrent)   
             return filePos - int64(bufSize)

这将采用文件中的当前位置并删除已创建的缓冲区。

请注意,返回的值是文件中的位置,而不是在此函数调用中读取的字节数。


查看完整回答
反对 回复 2022-10-04
  • 1 回答
  • 0 关注
  • 63 浏览
慕课专栏
更多

添加回答

举报

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