如何从文件中获取特定行

时间:2010-10-25 12:06:35

标签: ruby file-io

是否可以从知道其行号的文件中提取特定行?例如,只需将行N的内容作为文件“text.txt”中的字符串获取?

7 个答案:

答案 0 :(得分:22)

您可以通过readlines的索引获取它。

line = IO.readlines("file.txt")[42]

只有当它是一个小文件时才使用它。

答案 1 :(得分:14)

尝试以下两种解决方案之一:

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

答案 2 :(得分:4)

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无法跟上,那么这样做可能会成为一个问题。
  • 您只能从文件中读取所需的行。如果你的文件有1000行,那么获取第20行只会将第20行读入Ruby。

如果您想提出错误(gets)而不是在传递越界行时返回nil,则可以将readline替换为EOFError

答案 3 :(得分:3)

文件有一个很好的lineno方法。

def get_line(filename, lineno)
  File.open(filename,'r') do |f|
     f.gets until f.lineno == lineno - 1
     f.gets
  end
end

答案 4 :(得分:2)

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

答案 5 :(得分:0)

如果您想要一个衬垫并且不关心内存使用情况,请使用(假设线条从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

答案 6 :(得分:0)

如果您只希望文件中的一行,或者希望文件中的多行足够小以便重复读取,则可以使用这些解决方案。大型文件(例如,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

此解决方案适用于任意数量的行,不会将整个文件加载到内存中,只会读取尽可能少的行,并且只能读取一次文件。