2010-06-02 5 views
2

Je lis un fichier de 10 Mo de taille et qui contient des identifiants. Je les lis dans une liste en rubis. Je suis préoccupé par le fait que cela pourrait causer des problèmes de mémoire à l'avenir, lorsque le nombre d'ID dans le fichier pourrait augmenter. Existe-t-il un moyen efficace de lire un gros fichier par lots?Ruby - Lire le fichier par lots

Merci

Répondre

3

Il n'y a pas de manière universelle.

1) vous pouvez lire le fichier par morceaux:

File.open('filename','r') do |f| 
    chunk = f.read(2048) 
    ... 
end 

inconvénient: vous pouvez manquer un si substring serait entre les morceaux, à savoir que vous recherchez « SOME_TEXT », mais « SOME_ » est un dernier 5 octets de 1er morceau 2048 octets, et « TEXT » est un 4 octets de 2ème morceau

2), vous pouvez lire le fichier ligne par ligne

File.open('filename','r') do |f| 
    line = f.gets 
    ... 
end 

inconvénient: cette façon, il serait 2x..5x plus lente que la première méthode

9

Avec Lazy Enumerators et each_slice, vous pouvez obtenir le meilleur des deux mondes. Vous n'avez pas besoin de vous soucier de couper des lignes au milieu et vous pouvez parcourir plusieurs lignes dans un lot. batch_size peut être choisi librement.

header_lines = 1 
batch_size = 2000 

File.open("big_file") do |file| 
    file.lazy.drop(header_lines).each_slice(batch_size) do |lines| 
    # do something with batch of lines 
    end 
end 

Il pourrait être utilisé pour importer un énorme fichier CSV dans une base de données:

require 'csv' 
batch_size = 2000 

File.open("big_data.csv") do |file| 
    headers = file.first 
    file.lazy.each_slice(batch_size) do |lines| 
    csv_rows = CSV.parse(lines.join, write_headers: true, headers: headers) 
    # do something with 2000 csv rows, e.g. bulk insert them into a database 
    end 
end 
+1

Je me suis vaguement souvenu, est la réponse que je cherchais. La bonne façon de lire un fichier! –

+0

comment cela devrait-il fonctionner? Quel est le but de l'utilisation de «paresseux»? – Ilya

+0

J'ai fait quelques benchmarks avec une énorme quantité de données, l'utilisation de la mémoire est la même que sans chaîne '.lazy.each_slice'. – Ilya