2009-11-13 5 views
4

J'ai des informations sur 12340 voitures. Cette information est stockée de façon séquentielle dans deux fichiers différents:Traiter deux fichiers en même temps en Python

  1. car_names.txt, qui contient une ligne pour le nom de chaque voiture
  2. car_descriptions.txt, qui contient les descriptions de chaque voiture. Donc, 40 lignes pour chacun, où la 6e ligne se lit

Je voudrais faire @CAR_NAME en python: à ajouter pour chaque voiture dans le car_descriptions.txt déposer le nom de chaque voiture (qui vient de l'autre fichier) dans la ligne 7 (il est vide), juste après @CAR_NAME

Je pensais:

1) lire les noms de fichiers et voitures 1er magasin dans une matrice/liste 2) commencent à lire le fichier 2 et chaque fois qu'il trouve la chaîne @CAR_NAME, il suffit d'écrire le nom sur la ligne suivante

Mais je me demande s'il y a une approche plus rapide, donc le programme lit chaque fois une ligne de chaque fichier et fait la modification.

Merci

+1

Le 6e, 46e, 86e, ligne etc dans le second fichier contient le littéral '@ CAR_NAME' ? – eduffy

+0

exactement! que c'est – flow

+3

Est-ce que la vitesse est vraiment importante? Je peux lire 400 000 lignes de texte en clair avec python en moins d'une seconde. Combien de temps avez-vous besoin? –

Répondre

8

Je ne sais pas si je comprends parfaitement ce que vous essayez de faire, est-ce quelque chose comme ça?

f1 = open ('car_names.txt') 
f2 = open ('car_descriptions.txt') 
for car_name in f1.readlines(): 
     for i in range (6): # echo the first 6 lines 
       print f2.readline() 
     assert f2.readline() == '@CAR_NAME' # skip the 7th, but assert that it is @CAR_NAME 
     print car_name # print the real car name 
     for i in range (33): # print the remaining 33 of the original 40 
       print f2.readline() 
+0

oui, je suppose! Je vais vérifier maintenant! merci – flow

0
for line1, line2 in zip(file(filename1), file(filename2)): 
    # do your thing 

ou similaire

+0

Que fait "zip" ici? – flow

+1

Il entrelace les éléments d'une liste d'itérations. Vous pouvez utiliser itertools.izip comme alternative. –

+0

Dans ce cas précis, il renvoie une liste de tuples, chaque ligne étant (ligne x de fichier1, ligne x de fichier2) –

0

12340 ne sont pas des données (dans le sens qu'il ya des données beaucoup plus importantes à traiter sur le marché).

Encore meilleure approche utiliserait construire dans le module sqlite. Si ce n'est pas le cas, utilisez un format simple comme CSV par exemple. C'est une structure organisée. Si vous n'utilisez pas de threads, vous pouvez traiter deux fichiers simultanément.

+0

ce module sqlite peut-il être utilisé à partir de python? Comment? – flow

+0

importer sqlite3 http://docs.python.org/library/sqlite3.html – bua

4

lecture car_names.txt vous permettra d'économiser une quantité de mémoire piddling (vraiment très petit par rapport aux normes d'aujourd'hui ;-) mais absolument ne sera pas plus vite que siphonage vers le bas d'un seul coup (le meilleur cas, il sera exactement la même vitesse, probablement même un peu plus lente à moins que votre système d'exploitation sous-jacent et votre système de stockage ne fassent un excellent travail dans la mise en cache/la mise en mémoire cache de readahead). Je suggère donc:

import fileinput 

carnames = open('car_names.txt').readlines() 
carnamit = iter(carnames) 

skip = False 
for line in fileinput.input(['car_descriptions.txt'], True, '.bak'): 
    if not skip: 
    print line, 
    if '@CAR_NAME' in line: 
    print next(carnamit), 
    skip = True 
    else: 
    skip = False 

mesurent donc la vitesse de ce fait, et une alternative qui ne

carnamit = open('car_names.txt') 

au départ au lieu de lire toutes les lignes sur une liste comme ma première version - Je parie que la première version (dans la mesure où il y a une différence mesurable et reproductible) s'avérera plus rapide. BTW, le module d'entrée de fichier de la bibliothèque standard est documenté here, et c'est vraiment un moyen pratique d'effectuer "réécriture virtuelle sur place" de fichiers texte (en conservant généralement l'ancienne version comme une sauvegarde, juste au cas où - mais même si la machine doit tomber en panne au milieu de l'opération, l'ancienne version des données sera toujours là, donc dans un sens, la "réécriture" fonctionne de manière atomique par rapport aux plantages, un joli petit contact ;-).

+0

salut, excusez-moi, je comprends votre approche, mais j'obtiens l'erreur: NameError: nom 'Next' n'est pas défini ai-je manqué une autre bibliothèque? – flow

+0

Je crois que la prochaine est nouvelle dans Python 2.6. Courez-vous une version antérieure? –

+0

Dans 2.5 ou plus tôt, vous avez besoin de 'carnamit.next()' au lieu du 'next (carnamit)' plus agréable qui fonctionne dans 2.6 et plus tard. –

9

D'abord, créez un générateur qui récupère le nom de la voiture à partir d'une séquence.Vous pourriez donner chaque 7ème ligne; Je l'ai fait le rendement de la mine quelle que soit la ligne suit la ligne qui commence par @CAR_NAME:

def car_names(seq): 
    yieldnext=False 
    for line in seq: 
     if yieldnext: yield line 
     yieldnext = line.startswith('@CAR_NAME') 

Maintenant, vous pouvez utiliser itertools.izip passer par les deux séquences en parallèle:

from itertools import izip 
with open(r'c:\temp\cars.txt') as f1: 
    with open(r'c:\temp\car_names.txt') as f2: 
     for (c1, c2) in izip(f1, car_names(f2)): 
      print c1, c2 
+1

Qui vous a dit que c'était des fenêtres? – Davide

+18

Je teste le code que je poste. Si le fait que vous puissiez en déduire que ma machine fonctionne sous Windows vous gêne, je vous suggère de vous allonger dans une pièce calme et sombre avec un gant de toilette frais et humide sur vos yeux jusqu'à ce que la sensation passe. –

+2

Wow, quelle réponse chauffée à ma question! On dirait que vous avez besoin de la débarbouillette cool plus que moi! Quoi qu'il en soit, mon commentaire n'était qu'une triste note: les utilisateurs de Windows ont souvent tendance à penser que tout le monde est un utilisateur de Windows. Vous pouvez tester votre script avec un fichier dans le même répertoire (comme cet autre gars http://stackoverflow.com/questions/1731102/process-two-files-at-the-same-time-in-python/1731180#1731180) ou vous pourriez avoir fait abstraction du chemin avec 'filename '. Améliorez votre réponse au lieu de déclamer! – Davide

0

Je pense que cela correspond à la question suivante:

  • il lit le fichier de description d'une ligne à la fois
  • quand il voit @CAR_NAME, il émet encore , mais remplace la ligne suivante dans le fichier de description avec la ligne suivante des noms de fichier

def merge_car_descriptions(namefile, descrfile): 
    names = open(namefile,'r') 
    descr = open(descrfile,'r') 
    for d in descr: 
     if '@CAR_NAME' in d: 
      yield d + names.readline() 
      descr.next() 
     else: 
      yield d 

if __name__=='__main__': 
    import sys 
    if len(sys.argv) != 3: 
     sys.exit("Syntax: %s car_names.txt car_descriptions.txt" % sys.argv[0]) 
    for l in merge_car_descriptions(sys.argv[1], sys.argv[2]): 
     print l, 
Questions connexes