2010-11-30 7 views
1

J'ai environ 500 000+ fichier txt pour environ 7+ gigs de données au total. J'utilise python pour les mettre dans une base de données sqlite. Je crée 2 tables, 1. est le pK et le lien hypertexte vers le fichier. Pour l'autre tableau, j'utilise un extracteur d'entité qui a été développé en perl par un collègue.Sous-processus Python; Je ne peux pas lire stdout

Pour ce faire, j'utilise subprocess.Popen(). Avant cette méthode, j'ouvrais le perl à chaque itération de ma boucle, mais c'était simplement trop cher pour être utile. J'ai besoin de la perl pour être dynamique, j'ai besoin de pouvoir renvoyer des données et quatrième et le processus ne se termine pas jusqu'à ce que je lui dise de le faire. Le perl a été modifié de sorte que perl accepte la chaîne complète d'un fichier en tant que stdin, et me donne un stdout quand il obtient un \ n. Mais j'ai du mal à lire les données ...

Si j'utilise communique, à l'itération suivante dans ma boucle mon sous-processus est terminé, j'obtiens une erreur d'E/S. Si j'essaie d'utiliser readline() ou read(), il se verrouille. Voici quelques exemples du comportement différent que j'expérimente.

Cela bloque mon système et j'ai besoin de forcer Python fermer pour continuer. Cela annule le sous-processus et j'obtiens une erreur d'E/S lors de l'itération suivante de ma boucle.

numberExtractor = subprocess.Popen(["C:\\Perl\\bin\\perl5.10.0.exe","D:\\MyDataExtractor\\extractSerialNumbers.pl"], stdout=subprocess.PIPE, stdin= subprocess.PIPE) 
for infile in glob.glob(self.dirfilename + '\\*\\*.txt'): 

    f = open(infile) 
    reportString = f.read() 
    f.close() 

    reportString = reportString.replace('\n',' ') 
    reportString = reportString.replace('\r',' ') 
    reportString = reportString +'\n' 
    numberExtractor.stdin.write(reportString) 
    x = numberExtractor.communicate() #Works good, I can see my STDOUT from perl but the process terminates and will not run on the next iteration 

    print x 

Si je l'exécute comme ceci, Il traverse tout le code très bien. la ligne d'impression est ', mode' rb 'à 0x015dbf08> pour chaque élément de mon dossier.

numberExtractor = subprocess.Popen(["C:\\Perl\\bin\\perl5.10.0.exe","D:\\MyDataExtractor\\extractSerialNumbers.pl"], stdout=subprocess.PIPE, stdin= subprocess.PIPE) 
for infile in glob.glob(self.dirfilename + '\\*\\*.txt'): 
    f = open(infile) 
    reportString = f.read() 
    f.close() 

    reportString = reportString.replace('\n',' ') 
    reportString = reportString.replace('\r',' ') 
    reportString = reportString +'\n' 

    numberExtractor.stdin.write(reportString) 
    x = numberExtractor.stdout    #I can not get the value of the object, but it runs through all my files fine. 

    print x 

Si tout va bien je fais une simple erreur, mais est-il un moyen je peux envoyer un fichier à mon perll (stdin), obtenir le stdout, puis répéter sans avoir à rouvrir mon sous-processus pour chaque fichier ma boucle?

+0

Le programme Perl peut-il être facilement traduit en Python? Ce programme peut-il être facilement traduit en Perl? Moins de complexité aidera ici. – nmichaels

+0

Ce n'est pas vraiment une option dans ce cas, c'était ma première pensée avant même que j'ai commencé cette route. – dfarni

Répondre

2

Envisagez d'utiliser le shell. La vie est plus simple. Ne vous trompez pas lorsque Python démarre perl et tout ça. Il suffit de lire les résultats de perl et de traiter ces résultats en Python.

Étant donné que les deux processus s'exécutent simultanément, cela a tendance à être assez rapide et à utiliser beaucoup de ressources de l'UC sans beaucoup de programmation de votre part.

Dans le programme Python (load_database.py), vous pouvez simplement utiliser le module fileinput pour lire le fichier entier fourni sur stdin.

import fileinput 
for line in fileinput.input(): 
    load the row into the database 

C'est tout ce dont vous avez besoin dans le programme Python si vous faites la coquille faire le sale boulot de la mise en place du gazoduc.

+0

+1 pour recommander le shell. Mais pourquoi utiliser fileinput dans ce cas particulier au lieu du plus simple "for line in sys.stdin"? – tokland

+0

@tokland: (1) ce n'est pas beaucoup plus simple. (2) à long terme, la manipulation de pipe vs '<' redirect vs. liste de noms de fichiers est triviale quand 'fileinput'. –

+0

Je cours ceci sur une machine de Windows – dfarni

Questions connexes