2010-10-25 4 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 получать линии п + 1? –

+0

@ Марк Томас, в # 1 тоже. Я предположил, что индексирование с 0. – Nakilon

+0

Спасибо за '[* File.open ('...')]', не знал, что 'to_a' для экземпляра File может дать мне свои строки – tig

18

Вы можете получить его по индексу от readlines.

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

Используйте это только в том случае, если это небольшой файл.

+1

Правильный ответ –

+0

Это только правильный ответ, если файл небольшой, меньше пары МБ. В противном случае это заставит Ruby сразу загрузить весь файл, что в случае большого файла будет медленнее, чем использование решения 'foreach' или' get'.См. Http://stackoverflow.com/questions/25189262/why-is-slurping-a-file-bad, который содержит контрольные показатели. –

+0

Я был удивлен, узнав, что это займет всего несколько МБ! –

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, таким образом, вы не читать весь файл в память. Это может стать проблемой, если файл имеет размер 20 Мбайт, и вы достаточно часто читаете, чтобы GC не ускорялся.
  • Вы читаете только файл до нужной строки. Если ваш файл имеет 1000 строк, строка 20 будет читать только 20 первых строк в Ruby.

Вы можете заменить gets с readline, если вы хотите, чтобы вызвать ошибку (EOFError) вместо того, чтобы возвращать ноль при пропускании недоступных линий.

+2

Вы слишком долго писали в C ... – Nakilon

+0

Хе-хе, это то, что вы получаете от коллег-рубистов, когда пытаетесь написать оптимизированный код, а? :) –

+0

На разных языках вы должны оптимизировать разные вещи. – Nakilon

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

+0

Это продолжает чтение файла, когда линия уже найдена. – steenslag

+0

Не имеет значения. Если номер строки является последней второй строкой, например, она должна читать до этой строки ... – ghostdog74

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}'. –

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 
Смежные вопросы