在go中读取文本文件中的随机行

时间:2014-04-05 00:14:48

标签: go random-access

我正在使用encoding/csv来读取和解析非常大的.csv文件 我需要随机选择线条并通过一些测试 我目前的解决方案是读取整个文件,如

reader := csv.NewReader(file)
lines, err := reader.ReadAll()

然后从lines中随机选择行 显而易见的问题是需要很长时间才能阅读整个内容并且需要大量内存。

问题:
我的问题是,encoding/csv给了我io/reader有没有办法用它来读取随机线而不是一次加载整个东西?
这更多地是为了了解io/reader而非实际问题的好奇心,因为最终读取它并在内存中访问它更有效率,以便继续寻找随机线在磁盘上。

5 个答案:

答案 0 :(得分:4)

Apokalyptik的回答是最接近你想要的。读者是飘带,所以你不能只是跳到一个随机的地方(本身)。

天真地选择你在读取时保留任何给定行的概率可能会导致问题:你可能会在没有足够的输入行的情况下到达文件的末尾,或者你可能太快拿着行和没有得到一个好的样本。要么比正确猜测要大得多,因为你事先并不知道文件中有多少行(除非你先迭代它一次来计算它们)。

您真正需要的是 reservoir sampling

基本上,逐行读取文件。每一行,你选择是否按下它:你读的第一行,你有1/1的机会持有它。阅读第二行后,您1/2有机会用这个替换你所持有的内容。在第三行之后,您有1/2 * 2/3 = 1/3机会保留该行。因此,1/N有机会保留任何给定的行,其中N是您已读入的行数。这里是more detailed look at the algorithm(不要&#39}尝试仅从我在本段中告诉你的内容来实现它。

答案 1 :(得分:2)

最简单的解决方案是在您阅读每一行时做出决定,无论是测试还是抛弃它......让您的决定随意,这样您就不需要将整个内容保留在RAM中...然后在运行测试后传递文件...您也可以使用非随机分布测试(例如,在X字节或x行等之后)执行相同的样式

答案 2 :(得分:1)

我的建议是提前随机化输入文件,例如使用shuf

http://en.wikipedia.org/wiki/Shuf

然后你可以根据需要简单地读取前n行。

这无助于您了解有关io /读者的更多信息,但可能会解决您的问题。

答案 3 :(得分:0)

encoding/csv没有给你一个io.Reader它会给你一个csv.Reader(注意csv.NewReader [1]的定义缺乏包装资格,表明{ {1}}它返回属于同一个包。

Reader只实现您在那里看到的方法,因此看起来没有办法做您想要的,而不是编写自己的CSV解析器。

[1] http://golang.org/pkg/encoding/csv/#NewReader

答案 4 :(得分:0)

我也有类似的需求:从海量文本文件中随机读取(特定)行。我写了一个程序包,我称之为ramcsv

它首先读取整个文件一次,并标记每行的字节偏移量(它将此信息存储在内存中,但不存储整行)。

当您请求行号时,它将透明地寻求正确的偏移量并为您提供csv解析的行。

(请注意,作为ramcsv.New的第二个参数传递的csv.Reader参数仅用于将设置复制到新的阅读器中。)毫无疑问,这可以提高效率,但是对于我来说已经足够了需要,使我免于将大约20GB的文本文件读入内存。