320 votes

Quelles sont les façons courantes de lire un fichier en Ruby ?

Quelles sont les façons courantes de lire un fichier en Ruby ?

Par exemple, voici une méthode :

fileObj = File.new($fileName, "r")
while (line = fileObj.gets)
  puts(line)
end
fileObj.close

Je sais que Ruby est extrêmement flexible. Quels sont les avantages/inconvénients de chaque approche ?

7 votes

Je ne pense pas que la réponse gagnante actuelle soit correcte.

0 votes

Cela répond-il à votre question ? Comment lire les lignes d'un fichier en Ruby

382voto

mckeed Points 6200

La méthode la plus simple si le fichier n'est pas trop long est la suivante :

puts File.read(file_name)

En effet, IO.read ou File.read ferme automatiquement le fichier, de sorte qu'il n'est pas nécessaire d'utiliser la fonction File.open avec un bloc.

21 votes

IO.read ou File.read ferment aussi automatiquement le dossier, bien que votre formulation donne l'impression qu'ils ne le font pas.

15 votes

Il a déjà dit "si le fichier n'est pas trop long". Cela convient parfaitement à mon cas.

283voto

fl00r Points 41855
File.open("my/file/path", "r") do |f|
  f.each_line do |line|
    puts line
  end
end
# File is closed automatically at end of block

Il est également possible de fermer explicitement le fichier après comme ci-dessus (passer un bloc à open le ferme pour vous) :

f = File.open("my/file/path", "r")
f.each_line do |line|
  puts line
end
f.close

15 votes

C'est loin d'être un langage idiomatique en Ruby. Utilisez foreach au lieu de open et de se passer de la each_line bloc.

8 votes

f.each { |line| ... } y f.each_line { |line| ... } semblent avoir le même comportement (du moins dans Ruby 2.0.0).

241voto

the Tin Man Points 69148

Méfiez-vous des fichiers "slurp". C'est le cas lorsque vous lisez tout le fichier en mémoire en une seule fois.

Le problème, c'est qu'il n'est pas très évolutif. Vous pourriez être en train de développer du code avec un fichier de taille raisonnable, puis le mettre en production et vous rendre compte soudainement que vous essayez de lire des fichiers mesurant des gigaoctets, et que votre hôte se bloque lorsqu'il essaie de lire et d'allouer de la mémoire.

L'entrée/sortie ligne par ligne est très rapide, et presque toujours aussi efficace que le slurp. C'est étonnamment rapide en fait.

J'aime utiliser :

IO.foreach("testfile") { |x| print "GOT ", x }

ou

File.foreach('testfile') { |x| print "GOT", x }

File hérite de IO, et foreach est en IO, donc vous pouvez utiliser l'un ou l'autre.

J'ai quelques points de repère montrant l'impact d'essayer de lire de gros fichiers via read par rapport à l'entrée/sortie ligne par ligne sur "https://stackoverflow.com/q/25189262/128421".

7 votes

C'est exactement ce que je recherchais. J'ai un fichier de cinq millions de lignes, et je ne voulais vraiment pas qu'il soit chargé en mémoire.

0 votes

Je me demande pourquoi le fichier "slurping" est appelé comme ça ? Selon ce dictionnaire slurp signifie "manger ou boire bruyamment".

2 votes

Cela vient de l'histoire de la programmation. Voici un point de départ perl.com/article/21/2013/4/21/Read-an-entire-file-into-a-string

75voto

Victor Klos Points 56

Vous pouvez lire le fichier en une seule fois :

content = File.readlines 'file.txt'
content.each_with_index{|line, i| puts "#{i+1}: #{line}"}

Lorsque le fichier est volumineux ou risque de l'être, il est généralement préférable de le traiter ligne par ligne :

File.foreach( 'file.txt' ) do |line|
  puts line
end

Parfois, vous souhaitez avoir accès à l'identifiant du fichier ou contrôler vous-même les lectures :

File.open( 'file.txt' ) do |f|
  loop do
    break if not line = f.gets
    puts "#{f.lineno}: #{line}"
  end
end

Dans le cas de fichiers binaires, vous pouvez spécifier un séparateur nul et une taille de bloc, comme suit :

File.open('file.bin', 'rb') do |f|
  loop do
    break if not buf = f.gets(nil, 80)
    puts buf.unpack('H*')
  end
end

Enfin, vous pouvez le faire sans bloc, par exemple lorsque vous traitez plusieurs fichiers simultanément. Dans ce cas, le fichier doit être explicitement fermé (amélioré selon le commentaire de @antinome) :

begin
  f = File.open 'file.txt'
  while line = f.gets
    puts line
  end
ensure
  f.close
end

Références : API fichier et le API IO .

2 votes

Il n'y a pas for_each dans Fichier ou IO. Utilisez foreach à la place.

1 votes

J'utilise généralement l'éditeur Sublime Text, avec le plugin RubyMarkers, pour documenter le code qui sera utilisé dans les réponses ici. Il permet de montrer très facilement les résultats intermédiaires, comme avec IRB. Le plugin Seeing Is Believing pour Sublime Text 2 est également très puissant.

1 votes

Excellente réponse. Pour le dernier exemple, je pourrais suggérer d'utiliser while au lieu de loop et en utilisant ensure pour s'assurer que le fichier est fermé même si une exception est levée. Comme ceci (remplacez les points-virgules par des retours à la ligne) : begin; f = File.open('testfile'); while line = f.gets; puts line; end; ensure; f.close; end .

31voto

bta Points 22525

Une méthode simple consiste à utiliser readlines :

my_array = IO.readlines('filename.txt')

Chaque ligne du fichier d'entrée sera une entrée dans le tableau. La méthode gère l'ouverture et la fermeture du fichier pour vous.

5 votes

Comme avec read ou toute autre variante, le fichier entier sera placé en mémoire, ce qui peut causer des problèmes majeurs si le fichier est plus grand que la mémoire disponible. De plus, comme il s'agit d'un tableau, Ruby doit le créer, ce qui ralentit encore le processus.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X