【发布时间】:2011-04-30 04:26:43
【问题描述】:
是否可以从知道其行号的文件中提取特定行?例如,只需从文件“text.txt”中获取N 行的内容作为字符串?
【问题讨论】:
-
我真的被下面的很多答案误导了。恕我直言,最好的是this answer下面的评论:没有内存问题,直截了当。
是否可以从知道其行号的文件中提取特定行?例如,只需从文件“text.txt”中获取N 行的内容作为字符串?
【问题讨论】:
您可以通过索引从readlines 获取它。
line = IO.readlines("file.txt")[42]
只有在文件很小的情况下才使用它。
【讨论】:
foreach 或 gets 的解决方案要慢。请参阅包含基准的stackoverflow.com/questions/25189262/why-is-slurping-a-file-bad。
尝试以下两种解决方案之一:
file = File.open "file.txt"
#1 solution would eat a lot of RAM
p [*file][n-1]
#2 solution would not
n.times{ file.gets }
p $_
file.close
【讨论】:
[*File.open('…')],不知道文件实例的to_a 可以给我它的台词
cat -n 都这样做)
def get_line_from_file(path, line)
result = nil
File.open(path, "r") do |f|
while line > 0
line -= 1
result = f.gets
end
end
return result
end
get_line_from_file("/tmp/foo.txt", 20)
这是一个很好的解决方案,因为:
File.read,因此您不会将整个文件读入内存。如果文件有 20MB 大并且您经常阅读以致 GC 跟不上,这样做可能会成为问题。如果您想引发错误 (EOFError) 而不是在传递越界线时返回 nil,则可以将 gets 替换为 readline。
【讨论】:
times 时,你不需要 result = nil、return 并编写 C 风格的循环。
文件有一个很好的lineno 方法。
def get_line(filename, lineno)
File.open(filename,'r') do |f|
f.gets until f.lineno == lineno - 1
f.gets
end
end
【讨论】:
(lineno-1).times {f.gets}替换'直到'行。
linenumber=5
open("file").each_with_index{|line,ind|
if ind+1==linenumber
save=line
# break or exit if needed.
end
}
或
linenumber=5
f=open("file")
while line=f.gets
if $. == linenumber # $. is line number
print "#{f.lineno} #{line}" # another way
# break # break or exit if needed
end
end
f.close
如果你只是想拿线什么都不做,你可以使用这一个班轮
ruby -ne '(print $_ and exit) if $.==5' file
【讨论】:
如果你想要一个班轮并且不关心内存使用情况,请使用(假设行从 1 开始编号)
lineN = IO.readlines('text.txt')[n-1]
或
lineN = f.readlines[n-1]
如果您已经打开了文件。
否则最好这样做:
lineN = File.open('text.txt') do |f|
(n-1).times { f.gets } # skip lines preceeding line N
f.gets # read line N contents
end
【讨论】:
如果您只需要文件中的一行,或者如果您希望文件中的多行小到可以重复读取,这些解决方案就可以使用。大文件(例如 1000 万行)搜索特定行需要更长的时间,因此最好在一次读取中按顺序获取必要的行,这样大文件就不会被多次读取。
创建一个大文件:
File.open('foo', 'a') { |f| f.write((0..10_000_000).to_a.join("\n")) }
选择从中读取哪些行并确保它们已排序:
lines = [9_999_999, 3_333_333, 6_666_666].sort
打印出这些行:
File.open('foo') do |f|
lines.each_with_index do |line, index|
(line - (index.zero? ? 0 : lines[index - 1]) - 1).times { f.gets }
puts f.gets
end
end
此解决方案适用于任意数量的行,不会将整个文件加载到内存中,读取尽可能少的行,并且只读取一次文件。
【讨论】: