这有效:
f = File.new("myfile").readlines
f[0] #=> "line 1"
f[21] #=> "line 22"
但是如果我有一个非常大的文件,并且只需要读取几行怎么办。是否可以在 Ruby 中查找特定行并读取它们,而无需将文件加载到数组中?
我了解 IO 流,其中(如在标准输入的情况下)您不能随机搜索流。当然,必须有一种方法可以在不加载整个文件的情况下做到这一点。
这有效:
f = File.new("myfile").readlines
f[0] #=> "line 1"
f[21] #=> "line 22"
但是如果我有一个非常大的文件,并且只需要读取几行怎么办。是否可以在 Ruby 中查找特定行并读取它们,而无需将文件加载到数组中?
我了解 IO 流,其中(如在标准输入的情况下)您不能随机搜索流。当然,必须有一种方法可以在不加载整个文件的情况下做到这一点。
不要忽视IO
课堂。 IO::foreach
是返回 Enumerator 的方法之一,并且可以延迟计算。
IO#each_line
也是另一个将返回枚举器的。
在 Ruby 2.0 中,我们可以调用.lazy
和使用这些方法,除了 zip 和 cycle,它们允许我们遍历枚举而不将整个文件放入内存。
为此,您可以使用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
,您可以保证文件在块执行结束时正确关闭。
Update该with_index
方法接受一个可选参数来指定要使用的起始索引,因此上面的 che 代码可以更好地写成这样:
file.each_line.with_index(1) do |line, lineno|
case lineno
when 1
# line 1
end
end
我使用了 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]