Cela peut être plus rapide que le vôtre. Il ne fait aucune supposition sur la longueur des lignes. Il revient en arrière dans le fichier, un bloc à la fois, jusqu'à ce qu'il ait trouvé le bon nombre de ' \n des personnages.
def tail( f, lines=20 ):
total_lines_wanted = lines
BLOCK_SIZE = 1024
f.seek(0, 2)
block_end_byte = f.tell()
lines_to_go = total_lines_wanted
block_number = -1
blocks = [] # blocks of size BLOCK_SIZE, in reverse order starting
# from the end of the file
while lines_to_go > 0 and block_end_byte > 0:
if (block_end_byte - BLOCK_SIZE > 0):
# read the last block we haven't yet read
f.seek(block_number*BLOCK_SIZE, 2)
blocks.append(f.read(BLOCK_SIZE))
else:
# file too small, start from begining
f.seek(0,0)
# only read what was not read
blocks.append(f.read(block_end_byte))
lines_found = blocks[-1].count('\n')
lines_to_go -= lines_found
block_end_byte -= BLOCK_SIZE
block_number -= 1
all_read_text = ''.join(reversed(blocks))
return '\n'.join(all_read_text.splitlines()[-total_lines_wanted:])
Je n'aime pas les hypothèses délicates sur la longueur des lignes, alors que, dans la pratique, on ne peut jamais savoir ce genre de choses.
En général, cela permet de localiser les 20 dernières lignes lors du premier ou du deuxième passage dans la boucle. Si votre truc des 74 caractères est vraiment précis, vous faites la taille de bloc 2048 et vous aurez 20 lignes de queue presque immédiatement.
De plus, je ne brûle pas beaucoup de calories cérébrales en essayant d'affiner l'alignement avec des blocs OS physiques. En utilisant ces paquets d'E/S de haut niveau, je doute que vous puissiez constater une quelconque conséquence sur les performances en essayant de vous aligner sur les limites des blocs du système d'exploitation. Si vous utilisez des E/S de plus bas niveau, vous pourriez voir un gain de vitesse.
UPDATE
pour Python 3.2 et plus, suivez le processus sur les octets comme dans les fichiers texte In (ceux qui sont ouverts sans l'icône "b" dans la chaîne mode), seules les recherches relatives au début du fichier sont autorisées (l'exception étant la recherche jusqu'à la toute fin du fichier avec seek(0, 2)) :
eg : f = open('C:/.../../apache_logs.txt', 'rb')
def tail(f, lines=20):
total_lines_wanted = lines
BLOCK_SIZE = 1024
f.seek(0, 2)
block_end_byte = f.tell()
lines_to_go = total_lines_wanted
block_number = -1
blocks = []
while lines_to_go > 0 and block_end_byte > 0:
if (block_end_byte - BLOCK_SIZE > 0):
f.seek(block_number*BLOCK_SIZE, 2)
blocks.append(f.read(BLOCK_SIZE))
else:
f.seek(0,0)
blocks.append(f.read(block_end_byte))
lines_found = blocks[-1].count(b'\n')
lines_to_go -= lines_found
block_end_byte -= BLOCK_SIZE
block_number -= 1
all_read_text = b''.join(reversed(blocks))
return b'\n'.join(all_read_text.splitlines()[-total_lines_wanted:])
0 votes
Sur mon système (linux SLES 10), la recherche relative à la fin soulève une IOError "can't do nonzero end-relative seeks". J'aime cette solution mais je l'ai modifiée pour obtenir la longueur du fichier (
seek(0,2)
puistell()
), et utiliser cette valeur pour chercher par rapport au début.3 votes
Félicitations - cette question a été intégrée au code source de Kippo.
0 votes
Les paramètres de l
open
utilisée pour générer lef
doit être spécifié, car selon quef=open(..., 'rb')
of=open(..., 'rt')
elf
doivent être traitées différemment0 votes
J'ai décidé d'écrire une solution 100% généralisée pour cela, donc maintenant vous pouvez accéder à un gigantesque fichier texte comme une liste avec un découpage positif ou négatif arbitraire ex : [-2000:-1900] et ainsi de suite. github.com/SurpriseDog/readlines/blob/main/readlines.py