2010-10-25 7 views

Répondre

10

Essayez une de ces deux solutions:

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

solution est classé n ° 2 devient la ligne n + 1? –

+0

@ Mark Thomas, en # 1 aussi. Je supposé indexation de 0. – Nakilon

+0

Merci pour '[* File.open ('...')]', ne savais pas que 'to_a' pour l'instance de fichier peut me donner ses lignes – tig

18

Vous pouvez l'obtenir par l'indice de readlines.

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

N'utilisez ce code que s'il s'agit d'un petit fichier.

+1

Ceci est la bonne réponse –

+0

Ce n'est que la bonne réponse si le fichier est petit, moins de quelques MB. Sinon, cela forcera Ruby à charger le fichier entier en une fois, ce qui, dans le cas d'un fichier volumineux, est plus lent que d'utiliser une solution 'foreach' ou' gets'.Voir http://stackoverflow.com/questions/25189262/why-is-slurping-a-file-bad qui contient des repères. –

+0

J'ai été surpris d'apprendre que cela prend autant que quelques MB! –

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) 

Ceci est une bonne solution car:

  • Vous n'utilisez File.read, donc vous ne lisez pas le fichier en mémoire. Cela pourrait devenir un problème si le fichier a une taille de 20 Mo et que vous lisez assez souvent pour que le fichier GC ne fonctionne pas.
  • Vous lisez uniquement à partir du fichier jusqu'à la ligne souhaitée. Si votre fichier contient 1000 lignes, l'obtention de la ligne 20 ne lira que les 20 premières lignes dans Ruby.

Vous pouvez remplacer gets avec readline si vous souhaitez soulever une erreur (EOFError) au lieu de retourner nul lors du passage d'un hors-limites ligne.

+2

Vous avez écrit en C trop longtemps ... – Nakilon

+0

Hehe, c'est ce que vous obtenez de collègues Rubyists lorsque vous essayez d'écrire du code optimisé hein? :) –

+0

Dans différentes langues, vous devez optimiser différentes choses. – Nakilon

2
linenumber=5 
open("file").each_with_index{|line,ind| 
    if ind+1==linenumber 
    save=line 
    # break or exit if needed. 
    end 
} 

ou

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 

Si vous voulez juste pour obtenir la ligne et ne rien faire d'autre, vous pouvez utiliser cette ligne

ruby -ne '(print $_ and exit) if $.==5' file 
+0

Nice. C'est alors que les variables $ globales deviennent utiles. – Nakilon

+0

Cela continue à lire le fichier lorsque la ligne est déjà trouvée. – steenslag

+0

Peu importe. Si le numéro de ligne est la dernière ligne par exemple, il doit aussi lire jusqu'à cette ligne ... – ghostdog74

1

fichier a une méthode lineno agréable.

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

Vous n'avez pas vraiment besoin de lineno(). Vous pouvez remplacer la ligne 'until' par '(lineno-1) .times {f.gets}'. –

0

Si vous voulez une chemise et ne se soucient pas de l'utilisation de la mémoire, utilisez (lignes en supposant sont numérotés de 1)

lineN = IO.readlines('text.txt')[n-1] 

ou

lineN = f.readlines[n-1] 

si vous avez déjà le fichier ouvert .

Sinon, il serait préférable de le faire comme ceci:

lineN = File.open('text.txt') do |f| 
      (n-1).times { f.gets } # skip lines preceeding line N 
      f.gets     # read line N contents 
     end 
Questions connexes