2009-12-18 7 views
2

Je dois télécharger une archive zip de fichiers texte, envoyer chaque fichier texte de l'archive à d'autres gestionnaires pour traitement, et enfin écrire le fichier texte décompressé sur le disque.Lire le même fichier plusieurs fois en Python

J'ai le code suivant. Il utilise plusieurs ouvrir/fermer sur le même fichier, ce qui ne semble pas élégant. Comment puis-je le rendre plus élégant et efficace?

zipped = urllib.urlopen('www.abc.com/xyz.zip') 
buf = cStringIO.StringIO(zipped.read()) 
zipped.close() 
unzipped = zipfile.ZipFile(buf, 'r') 
for f_info in unzipped.infolist(): 
    logfile = unzipped.open(f_info) 
    handler1(logfile) 
    logfile.close() ## Cannot seek(0). The file like obj does not support seek() 
    logfile = unzipped.open(f_info) 
    handler2(logfile) 
    logfile.close() 
    unzipped.extract(f_info) 
+0

Pour clarifier les choses, le problème provient de l'absence d'un 'seek (0)' sur l'objet retourné par zipfile.open(), non? Vous voulez éviter plusieurs ouvertures sur le fichier zip? – rossipedia

+0

Bryan, vous avez la bonne idée. – hli

Répondre

5

Votre réponse est dans votre exemple de code. Il suffit d'utiliser StringIO pour tamponner le fichier journal:

zipped = urllib.urlopen('www.abc.com/xyz.zip') 
buf = cStringIO.StringIO(zipped.read()) 
zipped.close() 
unzipped = zipfile.ZipFile(buf, 'r') 
for f_info in unzipped.infolist(): 
    logfile = unzipped.open(f_info) 
    # Here's where we buffer: 
    logbuffer = cStringIO.StringIO(logfile.read()) 
    logfile.close() 

    for handler in [handler1, handler2]: 
     handler(logbuffer) 
     # StringIO objects support seek(): 
     logbuffer.seek(0) 

    unzipped.extract(f_info) 
1

Vous pourriez dire quelque chose comme:

handler_dispatch(logfile) 

et

def handler_dispatch(file): 
    for line in file: 
     handler1(line) 
     handler2(line) 

ou même le rendre plus dynamique en construisant une classe Handler avec de multiples fonctions handlerN, et l'application de chacun d'eux à l'intérieur handler_dispatch. Comme

class Handler: 
    def __init__(self:) 
     self.handlers = [] 

    def add_handler(handler): 
     self.handlers.append(handler) 

    def handler_dispatch(self, file): 
     for line in file: 
      for handler in self.handlers: 
       handler.handle(line) 
+1

+1: Si les gestionnaires n'ont pas besoin d'accéder au fichier entier à la fois, alors c'est une très bonne solution. –

+0

Oui, j'aurais dû le préciser. Merci. – danben

+0

C'est une idée intéressante, danben. Mais mes gestionnaires ont besoin de garder une trace des états lors du traitement des fichiers texte, donc l'alimentation d'une ligne à la fois ne fonctionnera pas sans quelques modifications. – hli

1

Ouvrez le fichier zip une fois, boucle à travers tous les noms, extraire le fichier pour chaque nom et processus, puis l'écrire sur le disque.

comme ceci:

for f_info in unzipped.info_list(): 
    file = unzipped.open(f_info) 
    data = file.read() 
    # If you need a file like object, wrap it in a cStringIO 
    fobj = cStringIO.StringIO(data) 
    handler1(fobj) 
    handler2(fobj) 
    with open(filename,"w") as fp: 
     fp.write(data) 

Vous avez l'idée