Ruby:开始在大文件中的任意点读取

时间:2010-11-05 02:55:21

标签: ruby flat-file

我有一些我希望筛选的日志文件。内容正是您在日志文件中所期望的:许多单行逗号分隔文本。这些文件大约每个4演出。其中一个File.each_line或foreach大约需要20分钟。

由于一个简单的foreach似乎......简单(而且很慢),我认为如果我只能告诉他们从哪里开始,两个独立的线程可能能够在同一个文件上工作。但基于我(有限的)知识,我无法确定这是否可能。

有没有办法在任意一行开始读取文件?

4 个答案:

答案 0 :(得分:3)

为了看看整个文件一次又一次地诋毁整个文件有什么区别,我测试了一个大约99MB的文件,超过1,000,000行。

greg-mbp-wireless:Desktop greg$ wc filelist.txt 
 1003002 1657573 99392863 filelist.txt

我将以下循环放入ruby文件中,并使用time命令从命令行运行它:

IO.read(ARGV.first).lines { |l|
}

greg-mbp-wireless:Desktop greg$ time ruby test.rb filelist.txt 

real    0m1.411s
user    0m0.653s
sys     0m0.169s

然后我将其更改为逐行阅读并定时:

IO.readlines(ARGV.first) { |l|
}

greg-mbp-wireless:Desktop greg$ time ruby test.rb filelist.txt 

real    0m1.053s
user    0m0.741s
sys     0m0.278s

我不知道为什么,但逐行阅读更快。这可能与内存分配有关,因为Ruby在第一个示例中尝试将整个文件加载到RAM中,或者可能是异常,因为我只为每个文件执行过一次测试。使用带有显式文件大小的read可能会更快,因为Ruby会知道需要提前分配多少。

这就是我需要测试的全部内容:

fcontent = ''
File.open(ARGV.first, 'r') do |fi|
  fsize = fi.size
  fcontent = fi.read(fsize)
end
puts fcontent.size

greg-mbp-wireless:Desktop greg$ time ruby test.rb filelist.txt 
99392863

real    0m0.168s
user    0m0.010s
sys     0m0.156s

看起来知道需要阅读多少会产生很大的不同。

在循环中添加回字符串缓冲区会产生以下结果:

File.open(ARGV.first, 'r') do |fi|
  fsize = fi.size
  fi.read(fsize).lines { |l| 
  }
end

greg-mbp-wireless:Desktop greg$ time ruby test.rb filelist.txt 

real    0m0.732s
user    0m0.572s
sys     0m0.158s

这仍然是一项改进。

如果您使用了Queue并从负责读取文件的线程中提供了它,那么从传入文本的任何进程中消耗队列,那么您可能会看到更高的总吞吐量。

答案 1 :(得分:2)

如果你想从文件中的特定行开始,我建议你只需要尾随。

excerpt = `tail -m +5000 filename.log`

这将为您提供从第5000行到文件末尾的filename.log的内容。

答案 2 :(得分:1)

对于行,它可能有点困难,但您可以在文件中搜索到某个字节。

IO#seek (link)IO#pos (link)都允许您搜索文件中的给定字节。

答案 3 :(得分:0)

如果您还没有尝试更快的csv,如果仍然太慢,请使用c中包含原生扩展名的内容 - http://github.com/wwood/excelsior