2010-10-25 45 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