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

我需要在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)


有一种方法可以避免上面的循环,并在从我离开的地方重新启动时改善阅读时间?


RISEBY
浏览 64回答 1
1回答

慕桂英546537

这里的问题是内部使用缓冲读取器,因此当您执行时,您将获得基础文件上的位置,但读取了一些数据并且您没有使用它。encoding/csvfile.Seek(0, io.SeekCurrent)有两种可能的解决方案:一种是使用较低级别的实现,允许准确控制您所在的位置另一个是找出有多少缓冲数据。我将向您展示第二个选项的实现(请注意,这依赖于对包内部工作的一些了解,如果更改,可能会停止工作)encoding/csv首先,在创建 csv 之前创建一个新的缓冲 io 读取器:&nbsp; &nbsp; //Position the file pointer to the start point&nbsp; &nbsp; &nbsp; &nbsp; file.Seek(startAt, io.SeekStart)&nbsp; &nbsp; &nbsp; &nbsp; bReader := bufio.NewReader(file)&nbsp; &nbsp; &nbsp; &nbsp; //Create a reader&nbsp; &nbsp; &nbsp; &nbsp; reader := csv.NewReader(bReader)这将允许您访问缓冲区。您可以像以前一样使用此读取器,但最终您可以通过以下方式计算文件上的最终位置:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bufSize&nbsp;:=&nbsp;bReader.Buffered() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filePos,&nbsp;err&nbsp;:=&nbsp;file.Seek(0,&nbsp;io.SeekCurrent)&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;filePos&nbsp;-&nbsp;int64(bufSize)这将采用文件中的当前位置并删除已创建的缓冲区。请注意,返回的值是文件中的位置,而不是在此函数调用中读取的字节数。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go