2010-10-25 40 views

回答

10

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

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 
+1

是解决方案#2线获得N + 1? – 2010-10-25 13:18:20

+0

@马克托马斯,排名第一。我假设索引从0 – Nakilon 2010-10-25 13:25:06

+0

感谢'[* File.open('...')]',不知道'to_a'文件实例可以给我它的行 – tig 2010-10-25 14:24:53

18

您可以通过指数从readlines得到它。

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

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

+1

这是正确的答案 – 2013-03-24 00:49:48

+0

这只是正确的答案,如果文件很小,少于几MB。否则,它会强制Ruby一次加载整个文件,这对于大文件来说比使用基于'foreach'或'gets'的解决方案要慢。请参阅http://stackoverflow.com/questions/25189262/why-is-slurping-a-file-bad其中包含基准。 – 2015-12-14 18:11:51

+0

我很惊讶地发现它需要多达几MB的空间! – 2015-12-15 07:42:26

3
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的第一行。

你可以,如果你想提高一个错误(EOFError),而不是通过一个彻头彻尾的越界线的时候返回nil与readline取代gets

+2

您在C中写的太长了...... – Nakilon 2010-10-25 12:25:59

+0

呵呵,这就是您从Ruby Rubyists那里得到的,当您尝试编写优化代码eh? :) – 2010-10-25 12:30:51

+0

用不同的语言,你必须优化不同的东西。 – Nakilon 2010-10-25 12:33:48

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 
+0

不错。那时全局$变量变得有用。 – Nakilon 2010-10-25 13:27:13

+0

当该行已被找到时,这将继续读取该文件。 – steenslag 2010-10-25 13:57:16

+0

没关系。例如,如果行号是最后一行第二行,那么它必须读取该行以及... – ghostdog74 2010-10-25 14:35:38

1

文件有一个很好的方法lineno

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

您并不需要lineno()。你可以用'(lineno-1).times {f.gets}'替换'until'行。 – 2010-10-25 14:44:58

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 
相关问题