6

这有效:

f = File.new("myfile").readlines
f[0] #=> "line 1"
f[21] #=> "line 22"

但是如果我有一个非常大的文件,并且只需要读取几行怎么办。是否可以在 Ruby 中查找特定行并读取它们,而无需将文件加载到数组中?

我了解 IO 流,其中(如在标准输入的情况下)您不能随机搜索流。当然,必须有一种方法可以在不加载整个文件的情况下做到这一点。

4

3 回答 3

7

不要忽视IO课堂。 IO::foreach是返回 Enumerator 的方法之一,并且可以延迟计算。

IO#each_line也是另一个将返回枚举器的。

在 Ruby 2.0 中,我们可以调用.lazy和使用这些方法,除了 zip 和 cycle,它们允许我们遍历枚举而不将整个文件放入内存。

于 2013-05-24T09:51:21.500 回答
5

为此,您可以使用each_line迭代器,结合获得with_index当前行的行号(从 0 开始计数):

File.open('myfile') do |file|

  file.each_line.with_index do |line, lineno|
    case lineno
    when 0
      # line 1
    when 21
      # line 22
    end   
  end

end

通过使用open, 将块传递给它,而不是new,您可以保证文件在块执行结束时正确关闭。


Updatewith_index方法接受一个可选参数来指定要使用的起始索引,因此上面的 che 代码可以更好地写成这样:

file.each_line.with_index(1) do |line, lineno|
  case lineno
  when 1
    # line 1
  end
end
于 2013-05-24T07:20:31.993 回答
2

我使用了 Jack 和 toro2k 的答案(大致相同的答案),但针对我自己的用例进行了修改。我可能想要的地方:打开一个文件,并寻找多个随机行,其中的顺序可能并不总是连续的。这就是我想出的(抽象的):

class LazyFile
    def initialize(file)
        @content = File.new(file)
    end

    def [](lineno)
        @content.rewind if @content.lineno > lineno
        skip = lineno - @content.lineno
        skip.times { @content.readline }
        @content.readline
    end
end

file = LazyFile("myfile")
file[1001]
于 2013-05-24T08:24:31.657 回答