2008-10-22 5 views
13

Je souhaite effectuer un filtrage de base sur un fichier. Lisez-le, faites le traitement, écrivez-le.Ouvrir un fichier, le lire, le traiter et le réécrire - la méthode la plus courte en Python

Je ne cherche pas le "golf", mais je veux la méthode la plus simple et la plus élégante pour y parvenir. Je suis venu avec:

from __future__ import with_statement 

filename = "..." # or sys.argv... 

with open(filename) as f: 
    new_txt = # ...some translation of f.read() 

open(filename, 'w').write(new_txt) 

La déclaration with rend les choses plus courtes que je n'ai pas explicitement ouvrir et fermer le fichier.

D'autres idées?

Répondre

25

En fait, un moyen plus facile l'utilisation fileinput est d'utiliser le paramètre inplace:

import fileinput 
for line in fileinput.input (filenameToProcess, inplace=1): 
    process (line) 

Si vous utilisez le paramètre inplace, il redirigera stdout vers votre fichier, de sorte que si vous faites une impression, il réécrira dans votre fichier.

Cet exemple ajoute les numéros de ligne à votre fichier:

import fileinput 

for line in fileinput.input ("b.txt",inplace=1): 
    print "%d: %s" % (fileinput.lineno(),line), 
+0

Très gentil, merci de pointer cette option. Vous pouvez également utiliser la fonction filelineno() de fileinput pour avoir automatiquement le numéro de ligne, sans le compter vous-même. –

+1

Oh, et vous avez oublié la virgule après l'impression - le code ajoute des sauts de ligne supplémentaires :-) –

+0

Merci d'avoir attrapé cela - J'ai changé l'exemple. – Hortitude

3

Cela semble fonctionner:

with open(filename, "r+") as f: 
    new_txt = process(f.read()) 
    f.truncate(0) 
    f.write(new_txt) 
+0

Works ici que lorsque vous appelez 'f.seek (0)' 'après f.truncate (0)', sinon le nouveau fichier commence par 11 zéro octets (Python 2.7.3 sous Linux). – scai

4

Je pencherais pour l'élégance d'une manière différente: mettre en œuvre vos opérations de lecture de fichiers et de filtrage en tant que générateurs, Vous écrivez plus de lignes de code, mais il sera plus code flexible, maintenable et performant.

Voir le Generator Tricks for Systems Programmers de David M. Beazley, ce qui est très important pour quiconque écrit ce type de code.

+0

Excellent lien - merci! Je suis un peu préoccupé par la difficulté accrue dans le débogage des pipelines, mais le pouvoir est indéniable. –

+1

Le développement piloté par les tests est votre ami. –

2

Si vous cherchez le python équivalent de "perl -pi", voici une assez bonne:

 
import fileinput 
for line in fileinput.input(): 
    # process line 

Voir http://www.python.org/doc/2.5.2/lib/module-fileinput.html pour plus.

Fait cette façon, vous pouvez utiliser votre script python dans un tube pour créer le nouveau fichier:

 
$ myscript.py infile.txt > outfile.txt 
+0

Cela ne m'aide pas vraiment, puisque je veux écrire dans le même fichier. Et la redirection ne fonctionnera pas de cette façon pour le même fichier –

1

Pour le faire d'une manière qui ne eat your data si vous tomber en panne au milieu:

from twisted.python.filepath import FilePath 
p = FilePath(filename) 
p.setContent(process(p.getContent())) 
0

Ma solution laide (mais à court comme indiqué dans la question) avec generator expressions;

# Some setup first 
file('test.txt', 'w').write('\n'.join('%05d' % i for i in range(100))) 


# This is the filter function 
def f(i): 
    return i % 3 


# This is the main part 
file('test2.txt', 'w').write('\n'.join(str(f(int(l))) for l in file('test.txt', 'r').readlines())) 


# And a wrapper for sanity 
def filter_file(infile, outfile, filter_function) 
    outfile.write('\n'.join(filter_function(l) for l in infile.readlines()))