J'ai besoin d'obtenir le nombre de lignes d'un gros fichier (des centaines de milliers de lignes) en python. Quelle est la manière la plus efficace à la fois en termes de mémoire et de temps?
En ce moment je fais:
def file_len(fname):
with open(fname) as f:
for i, l in enumerate(f):
pass
return i + 1
est-il possible de faire mieux?
python
text-files
line-count
SilentGhost
la source
la source
enumerate(f, 1)
et abandonner lei + 1
?Réponses:
Vous ne pouvez pas faire mieux que ça.
Après tout, toute solution devra lire l'intégralité du fichier, déterminer combien
\n
vous en avez et retourner ce résultat.Avez-vous une meilleure façon de procéder sans lire l'intégralité du fichier? Pas sûr ... La meilleure solution sera toujours liée aux E / S, le mieux que vous puissiez faire est de vous assurer que vous n'utilisez pas de mémoire inutile, mais il semble que vous ayez couvert cela.
la source
Une ligne, probablement assez rapide:
la source
Je pense qu'un fichier mappé en mémoire sera la solution la plus rapide. J'ai essayé quatre fonctions: la fonction publiée par l'OP (
opcount
); une simple itération sur les lignes du fichier (simplecount
); readline avec un fichier mappé en mémoire (mmap) (mapcount
); et la solution de lecture tampon proposée par Mykola Kharechko (bufcount
).J'ai exécuté chaque fonction cinq fois et calculé la durée d'exécution moyenne d'un fichier texte de 1,2 million de lignes.
Windows XP, Python 2.5, 2 Go de RAM, processeur AMD 2 GHz
Voici mes résultats:
Edit : nombres pour Python 2.6:
La stratégie de lecture du tampon semble donc être la plus rapide pour Windows / Python 2.6
Voici le code:
la source
wccount()
soit le gist.github.com/0ac760859e614cd03652J'ai dû poster ceci sur une question similaire jusqu'à ce que mon score de réputation ait un peu augmenté (merci à celui qui m'a cogné!).
Toutes ces solutions ignorent une façon d'accélérer considérablement l'exécution, à savoir en utilisant l'interface non tamponnée (brute), en utilisant des tableaux de bord et en effectuant votre propre mise en mémoire tampon. (Cela ne s'applique qu'à Python 3. Dans Python 2, l'interface brute peut ou non être utilisée par défaut, mais dans Python 3, vous utiliserez par défaut Unicode.)
En utilisant une version modifiée de l'outil de synchronisation, je pense que le code suivant est plus rapide (et légèrement plus pythonique) que toutes les solutions proposées:
En utilisant une fonction de générateur séparée, cela fonctionne plus rapidement:
Cela peut être fait complètement avec des expressions de générateurs en ligne à l'aide d'itertools, mais cela devient assez étrange:
Voici mes horaires:
la source
wccount
dans ce tableau pour l'wc
outil shell de sous-processus ?rawincount
solution moins étrange en utilisantbufgen = iter(partial(f.raw.read, 1024*1024), b'')
au lieu de combinertakewhile
etrepeat
.Vous pouvez exécuter un sous-processus et exécuter
wc -l filename
la source
Voici un programme python pour utiliser la bibliothèque multiprocesseurs pour distribuer le comptage de lignes sur les machines / cœurs. Mon test améliore le comptage d'un fichier de 20 millions de lignes de 26 secondes à 7 secondes en utilisant un serveur Windows 64 à 8 cœurs. Remarque: ne pas utiliser le mappage de mémoire rend les choses beaucoup plus lentes.
la source
Une solution bash d'une ligne similaire à cette réponse , utilisant la
subprocess.check_output
fonction moderne :la source
wc -l
prend ~ 5 secondes.shell=True
est mauvais pour la sécurité, il vaut mieux l'éviter.J'utiliserais la méthode d'objet fichier de Python
readlines
, comme suit:Cela ouvre le fichier, crée une liste de lignes dans le fichier, compte la longueur de la liste, l'enregistre dans une variable et ferme à nouveau le fichier.
la source
xreadlines
est obsolète depuis 2.3, car il ne fait que renvoyer un itérateur.for line in file
est le remplacement indiqué. Voir: docs.python.org/2/library/stdtypes.html#file.xreadlinesla source
Voici ce que j'utilise, semble assez propre:
MISE À JOUR: C'est légèrement plus rapide que l'utilisation de python pur, mais au détriment de l'utilisation de la mémoire. Le sous-processus va générer un nouveau processus avec la même empreinte mémoire que le processus parent pendant qu'il exécute votre commande.
la source
:-)
C'est la chose la plus rapide que j'ai trouvée en utilisant du python pur. Vous pouvez utiliser la quantité de mémoire que vous souhaitez en définissant un tampon, bien que 2 ** 16 semble être un point idéal sur mon ordinateur.
J'ai trouvé la réponse ici Pourquoi la lecture des lignes de stdin est-elle beaucoup plus lente en C ++ qu'en Python? et l'ajusté juste un tout petit peu. C'est une très bonne lecture pour comprendre comment compter les lignes rapidement, bien qu'il
wc -l
soit toujours environ 75% plus rapide qu'autre chose.la source
J'ai obtenu une petite amélioration (4-8%) avec cette version qui réutilise un tampon constant afin d'éviter toute surcharge mémoire ou GC:
Vous pouvez jouer avec la taille du tampon et peut-être voir une petite amélioration.
la source
La réponse de Kyle
est probablement le meilleur, une alternative pour cela est
Voici la comparaison des performances des deux
la source
Solution en une ligne:
Mon extrait:
la source
os.system()
dans une variable et la post-traiter de toute façon.Juste pour compléter les méthodes ci-dessus, j'ai essayé une variante avec le module fileinput:
Et passé un fichier de lignes de 60mil à toutes les méthodes indiquées ci-dessus:
C'est une petite surprise pour moi que l'entrée de fichier soit si mauvaise et évolue bien pire que toutes les autres méthodes ...
la source
Quant à moi, cette variante sera la plus rapide:
raisons: tampon plus rapide que la lecture ligne par ligne et
string.count
est également très rapidela source
Ce code est plus court et plus clair. C'est probablement le meilleur moyen:
la source
J'ai modifié le boîtier tampon comme ceci:
Désormais, les fichiers vides et la dernière ligne (sans \ n) sont également comptés.
la source
Et ça
la source
count = max(enumerate(open(filename)))[0]
la source
enumerate()
est le nombre de début selon docs.python.org/2/library/functions.html#enumeratela source
la source
Si l'on veut obtenir le nombre de lignes à moindre coût en Python sous Linux, je recommande cette méthode:
file_path peut être à la fois un chemin de fichier abstrait ou un chemin relatif. J'espère que cela peut vous aider.
la source
Que dis-tu de ça?
la source
Que diriez-vous de ce one-liner:
Prend 0,003 s en utilisant cette méthode pour le chronométrer sur un fichier de 3900 lignes
la source
la source
Méthode simple:
1)
2)
3)
la source
le résultat de l'ouverture d'un fichier est un itérateur, qui peut être converti en une séquence, qui a une longueur:
c'est plus concis que votre boucle explicite et évite le
enumerate
.la source
Vous pouvez utiliser le
os.path
module de la manière suivante:, où
Filename
est le chemin absolu du fichier.la source
os.path
?Si le fichier peut tenir en mémoire, alors
la source