2010-05-12 6 views
1

Je travaille actuellement avec des fichiers de très grande largeur fixe, parfois bien plus d'un million de lignes. J'ai écrit une méthode qui peut écrire sur les fichiers en fonction d'un ensemble de paramètres, mais je pense qu'il doit y avoir un moyen plus efficace d'y parvenir. Le code actuel J'utilise est:Le moyen le plus efficace pour écrire dans un fichier de largeur fixe (Ruby)

def self.writefiles(file_name, positions, update_value) 
@file_name = file_name 
@positions = positions.to_i 
@update_value = update_value 

line_number = 0 
@file_contents = File.open(@file_name, 'r').readlines 

    while line_number < @file_contents.length 
     @read_file_contents = @file_contents[line_number] 
     @read_file_contents[@positions] = @update_value 
     @file_contents[line_number] = @read_file_contents 
     line_number += 1 
    end 

write_over_file = File.new(@file_name, 'w') 
line_number = 0 

    while line_number < @file_contents.length 
     write_over_file.write @file_contents[line_number] 
     line_number += 1 
    end 

write_over_file.close 
end 

Par exemple, si la position 25 dans le fichier indiqué qu'il est un fichier d'origine la valeur est réglée sur « O » et si je voulais remplacer cette valeur I utiliserait ClassName.writefiles (filename, 140, "X") pour changer cette position sur chaque ligne. Toute aide pour rendre cette méthode plus efficace serait grandement appréciée!

Merci

Répondre

0
#!/usr/bin/ruby 
# replace_at_pos.rb 
pos, char, infile, outfile = $* 
pos = pos.to_i 
File.open(outfile, 'w') do |f| 
    File.foreach(infile) do |line| 
    line[pos] = char 
    f.puts line 
    end 
end 

et vous l'utilisez comme:

replace_at_pos.rb 140 X inputfile.txt outputfile.txt 

Pour remplacer ensemble de valeurs, vous pouvez utiliser un hachage:

replace = { 
    100 => 'a', 
    155 => 'c', 
    151 => 't' 
} 
. . . 
replace.each do |k, v| 
    line[k] = v 
end 
+0

Super, je vais devoir essayer cela et voir quel genre de boost de performance je reçois. Juste une question rapide pour vous ... Comment pourrais-je modifier cela si plus d'une position aurait besoin d'être changée. E.G Je dois mettre à jour la date dans les positions 100..107. Merci encore pour l'aide! –

+0

Hmmm juste utilisé le code que vous avez fourni et tout ce qu'il semble faire est de supprimer chaque ligne dans le fichier. –

+0

Première partie ou seconde? J'ai essayé le premier, ça marche bien. La seconde est juste une idée, pas un code de travail. –

1

Si c'est un fichier de largeur fixe , vous pouvez ouvrir le fichier pour lire/écrire et utiliser chercher pour aller au début des données que vous voulez écrire, et écrire seulement les données que vous voulez nging et pas toute la ligne. Cela serait probablement plus efficace que de réécrire le fichier entier pour remplacer un champ.

Voici un exemple grossier. Il lit le dernier champ (10,20,30) incrémente par 1, et l'écrit en arrière:

tha_file (10 caractères par ligne, y compris la ligne)

12 3 x 10 
23 4 x 20 
78 9 x 30 

seeker.rb

#!/usr/bin/env ruby 
fh=open("tha_file", "r+") 

$RECORD_WIDTH=10 
$POS=8 
$FIELD_WIDTH=2 

# seek to first field 
fh.seek($POS - 1, IO::SEEK_CUR) 

while !fh.eof? 

    cur_val=fh.read($FIELD_WIDTH).to_i 
    puts "read #{cur_val}" 
    fh.seek(-1 * $FIELD_WIDTH, IO::SEEK_CUR) 
    cur_val = cur_val + 1 

    fh.write(cur_val) 
    puts "wrote #{cur_val}" 

    # Move to start of next field in the middle of next record 
    fh.seek($RECORD_WIDTH - $FIELD_WIDTH, IO::SEEK_CUR) 
end 
+0

J'ai essayé cela avant d'aller avec la méthode utilisée ci-dessus et cela a malheureusement causé toutes sortes de problèmes. Je suppose que je n'utilisais Ruby que depuis environ une semaine à ce moment-là, alors je vais peut-être essayer de nouveau. –

+0

Pourriez-vous éventuellement me donner un exemple de ce que le code aurait l'air? Je ne peux pas sembler arrêter de chercher à changer la mise en forme du fichier chaque fois que j'insère de nouvelles valeurs.J'ai essayé de trouver des guides plus détaillés sur la façon de l'utiliser, mais chaque site semble donner le même exemple. Merci –

+0

Le problème est que vous devez toujours vous rappeler/exactement/où vous êtes dans le fichier et devez vous assurer d'écrire les champs dans la même largeur. Mon code ci-dessus ne vérifie pas la largeur et va passer de 99 à 100. – Shizzmo

0

Vous allez certainement gagner du temps et beaucoup de mémoire en retravaillant les programmes pour lire à partir du fichier une ligne à la fois (Vous lisez actuellement le fichier en mémoire). Vous écrivez ensuite à une copie de sauvegarde du fichier dans la boucle, puis renommez le fichier à la fin. Quelque chose comme ça. Cela impliquerait évidemment une gestion des erreurs autour de l'élément renommer, ce qui pourrait entraîner la perte de vos données d'entrée.

+0

Juste étalonné les deux méthodes, et malheureusement la méthode originale que j'ai utilisée est un peu plus rapide. Merci pour la contribution si! –

+0

Eh bien, c'est étrange que le mien a montré exactement le contraire. C'est-à-dire que la mine a fonctionné dans environ 2/3 du temps. (100 itérations sur un fichier de lignes 256k) Gave 102s vs 161s. Avez-vous couru alors dans le même processus? J'ai essayé cela mais il y avait très peu de mémoire après la première exécution, donc je les ai essayés dans des processus séparés. –

+0

Hmmm Je vais devoir essayer encore une fois, désolé j'ai manqué la mise à jour de votre poste hier. Merci! –

Questions connexes