J'écris une visionneuse de fichiers journaux pour une application Web et pour cela, je veux paginer à travers les lignes du fichier journal. Les éléments du fichier sont basés sur la ligne avec l'élément le plus récent en bas.
J'ai donc besoin d'une tail()
méthode capable de lire les n
lignes par le bas et de prendre en charge un décalage. Ce que j'ai trouvé ressemble à ceci:
def tail(f, n, offset=0):
"""Reads a n lines from f with an offset of offset lines."""
avg_line_length = 74
to_read = n + offset
while 1:
try:
f.seek(-(avg_line_length * to_read), 2)
except IOError:
# woops. apparently file is smaller than what we want
# to step back, go to the beginning instead
f.seek(0)
pos = f.tell()
lines = f.read().splitlines()
if len(lines) >= to_read or pos == 0:
return lines[-to_read:offset and -offset or None]
avg_line_length *= 1.3
Est-ce une approche raisonnable? Quelle est la méthode recommandée pour terminer les fichiers journaux avec des décalages?
seek(0,2)
alorstell()
), et j'utilise cette valeur pour rechercher par rapport au début.open
commande utilisée pour générer l'f
objet fichier doivent être spécifiés, car selon sif=open(..., 'rb')
ouf=open(..., 'rt')
lef
doit être traité différemmentRéponses:
Cela peut être plus rapide que le vôtre. Ne fait aucune hypothèse sur la longueur de la ligne. Parcoure le fichier un bloc à la fois jusqu'à ce qu'il trouve le bon nombre de caractères «\ n».
Je n'aime pas les hypothèses délicates sur la longueur des lignes quand - en pratique - on ne peut jamais savoir des choses comme ça.
Généralement, cela permettra de localiser les 20 dernières lignes sur le premier ou le deuxième passage dans la boucle. Si votre truc de 74 caractères est réellement précis, vous faites la taille de bloc de 2048 et vous suivrez 20 lignes presque immédiatement.
De plus, je ne brûle pas beaucoup de calories dans le cerveau en essayant d'affiner l'alignement avec les blocs OS physiques. En utilisant ces packages d'E / S de haut niveau, je doute que vous voyiez une conséquence sur les performances de la tentative d'alignement sur les limites des blocs du système d'exploitation. Si vous utilisez des E / S de niveau inférieur, vous verrez peut-être une accélération.
METTRE À JOUR
pour Python 3.2 et plus, suivez le processus sur octets car Dans les fichiers texte (ceux ouverts sans "b" dans la chaîne de mode), seules les recherches relatives au début du fichier sont autorisées (l'exception étant la recherche jusqu'à la fin du fichier avec seek (0, 2)):
par exemple:
f = open('C:/.../../apache_logs.txt', 'rb')
la source
io.UnsupportedOperation: can't do nonzero end-relative seeks
je peux changer le décalage à 0, mais cela va à l'encontre de l'objectif de la fonction.Suppose un système de type Unix sur Python 2 que vous pouvez faire:
Pour python 3, vous pouvez faire:
la source
offset_total = str(n+offset)
et remplacer cette lignestdin,stdout = os.popen2("tail -n "+offset_total+" "+f)
pour éviterTypeErrors (cannot concatenate int+str)
Voici ma réponse. Python pur. En utilisant timeit, cela semble assez rapide. Tailing 100 lignes d'un fichier journal qui a 100 000 lignes:
Voici le code:
la source
if len(lines_found) > lines:
vraiment nécessaire? Laloop
condition ne l' attraperait-elle pas également?os.SEEK_END
utilisé simplement pour plus de clarté? Autant que j'ai trouvé, sa valeur est constante (= 2). Je me demandais si je ne voulais pas le laisser de côté pour pouvoir laisser de côté leimport os
. Merci pour la bonne solution!os.SEEK_END
par son équivalent entier. C'était principalement là pour la lisibilité.while len(lines_found) < lines
enwhile len(lines_found) <= lines
dans ma copie. Merci!Si la lecture de l'ensemble du fichier est acceptable, utilisez un fichier deque.
Avant la version 2.6, deques n'avait pas d'option maxlen, mais c'est assez facile à implémenter.
S'il est nécessaire de lire le fichier à partir de la fin, utilisez une recherche au galop (alias exponentielle).
la source
pos *= 2
semble complètement arbitraire. Quelle est sa signification?La réponse de S.Lott ci-dessus fonctionne presque pour moi mais finit par me donner des lignes partielles. Il s'avère que cela corrompt les données sur les limites des blocs car les données contiennent les blocs lus dans l'ordre inverse. Lorsque '' .join (data) est appelé, les blocs sont dans le mauvais ordre. Cela corrige cela.
la source
Le code que j'ai fini par utiliser. Je pense que c'est le meilleur à ce jour:
la source
Solution simple et rapide avec mmap:
la source
.rfind
méthode pour rechercher les nouvelles lignes en arrière, plutôt que d'effectuer des vérifications octet à la fois au niveau Python; en CPython, en remplaçant le code de niveau Python par Les appels intégrés en C gagnent généralement beaucoup). Pour les entrées plus petites, ledeque
avec amaxlen
est plus simple et probablement aussi rapide.Une version compatible python3 encore plus propre qui n'insère pas mais ajoute et inverse:
utilisez-le comme ceci:
la source
Mettez à jour la solution @papercrane vers python3. Ouvrez le fichier avec
open(filename, 'rb')
et:la source
Publier une réponse à la demande des commentateurs sur ma réponse à une question similaire où la même technique a été utilisée pour muter la dernière ligne d'un fichier, pas seulement pour l'obtenir.
Pour un fichier de taille importante,
mmap
c'est la meilleure façon de le faire. Pour améliorer lammap
réponse existante , cette version est portable entre Windows et Linux, et devrait fonctionner plus rapidement (même si elle ne fonctionnera pas sans quelques modifications sur Python 32 bits avec des fichiers de la plage Go, voir l' autre réponse pour des conseils sur la gestion de cela , et pour modifier pour travailler sur Python 2 ).Cela suppose que le nombre de lignes suivies est suffisamment petit pour pouvoir les lire toutes en mémoire en toute sécurité; vous pouvez également en faire une fonction de générateur et lire manuellement une ligne à la fois en remplaçant la dernière ligne par:
Enfin, cette lecture en mode binaire (nécessaire à utiliser
mmap
) donc elle donne desstr
lignes (Py2) et desbytes
lignes (Py3); si vous voulezunicode
(Py2) oustr
(Py3), l'approche itérative pourrait être modifiée pour décoder pour vous et / ou corriger les nouvelles lignes:Remarque: j'ai tapé tout cela sur une machine sur laquelle je n'ai pas accès à Python pour tester. S'il vous plaît laissez-moi savoir si j'ai fait une faute de frappe; c'était assez similaire à mon autre réponse que je pense que cela devrait fonctionner, mais les ajustements (par exemple la gestion d'un
offset
) pourraient conduire à des erreurs subtiles. S'il vous plaît laissez-moi savoir dans les commentaires s'il y a des erreurs.la source
J'ai trouvé que le Popen ci-dessus était la meilleure solution. C'est rapide et sale et cela fonctionne Pour python 2.6 sur une machine Unix, j'ai utilisé ce qui suit
soutput contiendra les n dernières lignes du code. pour parcourir le soutput ligne par ligne, faites:
la source
basé sur la réponse la plus votée de S.Lott (25 septembre 2008 à 21:43), mais corrigé pour les petits fichiers.
J'espère que c'est utile.
la source
Il existe des implémentations existantes de tail sur pypi que vous pouvez installer à l'aide de pip:
Selon votre situation, il peut y avoir des avantages à utiliser l'un de ces outils existants.
la source
tailhead
,tailer
mais cela n'a pas fonctionné. Également essayémtFileUtil
. C'était initialement une erreur parce que lesprint
déclarations n'avaient pas de parenthèses (je suis sur Python 3.6). Je les ai ajoutésreverse.py
et les messages d'erreur ont disparu, mais lorsque mon script appelle le module (mtFileUtil.tail(open(logfile_path), 5)
), il n'imprime rien.Facile :
la source
Pour plus d'efficacité avec des fichiers très volumineux (courant dans les situations de fichier journal où vous voudrez peut-être utiliser tail), vous voulez généralement éviter de lire le fichier entier (même si vous le faites sans lire le fichier entier en mémoire à la fois). besoin de travailler en quelque sorte sur le décalage en lignes plutôt qu'en caractères. Une possibilité est de lire à l'envers avec seek () char par char, mais c'est très lent. Au lieu de cela, il est préférable de traiter des blocs plus grands.
J'ai une fonction utilitaire que j'ai écrite il y a quelque temps pour lire les fichiers à l'envers qui peuvent être utilisés ici.
[Modifier] Ajout d'une version plus spécifique (évite d'avoir à inverser deux fois)
la source
vous pouvez aller à la fin de votre fichier avec f.seek (0, 2) puis lire les lignes une par une avec le remplacement suivant pour readline ():
la source
Basé sur la réponse d'Eyecue (10 juin 10 à 21:28): cette classe ajoute la méthode head () et tail () à l'objet de fichier.
Usage:
la source
Plusieurs de ces solutions posent des problèmes si le fichier ne se termine pas par \ n ou si la première ligne complète est lue.
la source
Voici une implémentation assez simple:
la source
f.seek
? Pourquoi pas avant lewith open
? Aussi, pourquoi dans leexcept
vous faites unf.readlines()
??Il existe un module très utile qui peut faire cela:
la source
Une autre solution
si votre fichier txt ressemble à ceci: souris serpent chat lézard chien loup
vous pouvez inverser ce fichier en utilisant simplement l'indexation de tableau en python '' '
résultat: chien loup lézard chat
la source
Le moyen le plus simple est d'utiliser
deque
:la source
J'ai dû lire une valeur spécifique de la dernière ligne d'un fichier et je suis tombé sur ce fil. Plutôt que de réinventer la roue en Python, je me suis retrouvé avec un minuscule script shell, enregistré sous / usr / local / bin / get_last_netp:
Et dans le programme Python:
la source
Pas le premier exemple utilisant un deque, mais un plus simple. Celui-ci est général: il fonctionne sur n'importe quel objet itérable, pas seulement un fichier.
la source
la source
la source
la source
la source
Mise à jour pour réponse donnée par A.Coady
Fonctionne avec python 3 .
Cela utilise la recherche exponentielle et ne tamponnera que les
N
lignes de l'arrière et est très efficace.la source
Après réflexion, c'est probablement aussi rapide que n'importe quoi ici.
C'est beaucoup plus simple. Et cela semble se dérouler à un bon rythme.
la source