117 votes

Comment passer à une ligne particulière dans un énorme fichier texte ?

Existe-t-il des alternatives au code ci-dessous :

startFromLine = 141978 # or whatever line I need to jump to

urlsfile = open(filename, "rb", 0)

linesCounter = 1

for line in urlsfile:
    if linesCounter > startFromLine:
        DoSomethingWithThisLine(line)

    linesCounter += 1

Si je traite un énorme fichier texte (~15MB) avec des lignes de longueur inconnue mais différente, et avoir besoin de sauter à une ligne particulière dont je connais le numéro à l'avance ? Je me sens mal de les traiter une par une alors que je sais que je peux ignorer au moins la première moitié du fichier. Je cherche une solution plus élégante, s'il en existe une.

0 votes

Comment sais-tu que la première moitié du fichier n'est pas un tas de " \n "s" alors que la seconde moitié est une seule ligne ? Pourquoi vous sentez-vous mal à ce sujet ?

9 votes

Je pense que le titre est trompeur - en effet, 15 Mo n'est pas vraiment un "énorme fichier texte", c'est le moins qu'on puisse dire...

126voto

Adam Rosenfield Points 176408

Vous ne pouvez pas avancer sans avoir lu le fichier au moins une fois, puisque vous ne savez pas où se trouvent les sauts de ligne. Vous pourriez faire quelque chose comme :

# Read in the file once and build a list of line offsets
line_offset = []
offset = 0
for line in file:
    line_offset.append(offset)
    offset += len(line)
file.seek(0)

# Now, to skip to line n (with the first line being line 0), just do
file.seek(line_offset[n])

2 votes

+1, mais attention, cela n'est utile que s'il va sauter à plusieurs lignes aléatoires ! mais s'il ne saute qu'à une seule ligne, alors c'est du gaspillage.

3 votes

+1 : En outre, si le fichier ne change pas, l'index du numéro de ligne peut être conservé et réutilisé, ce qui permet d'amortir davantage le coût initial de l'analyse du fichier.

2 votes

OK, une fois que j'ai sauté là, comment dois-je procéder ligne par ligne en partant de cette position ?

34voto

John Ellinwood Points 6578

linecache :

Le site linecache permet de récupérer n'importe quelle ligne d'un fichier source Python, tout en essayant d'optimiser en interne, à l'aide d'un cache, le cas courant où de nombreuses lignes sont lues depuis un seul fichier. Ceci est utilisé par le module traceback pour récupérer les lignes de source à inclure dans la traceback formatée...

184 votes

Je viens de vérifier le code source de ce module : le fichier entier est lu en mémoire ! J'exclurais donc définitivement cette réponse pour accéder rapidement à une ligne donnée d'un fichier.

0 votes

MiniQuark, je l'ai essayé, il fonctionne vraiment, et très rapidement. Je dois voir ce qui se passe si je travaille sur une douzaine de fichiers en même temps de cette façon, pour savoir à quel moment mon système meurt.

6 votes

Le gestionnaire de mémoire virtuelle de votre système d'exploitation vous aide beaucoup, donc la lecture de gros fichiers en mémoire peut ne pas être lente si vous ne générez pas beaucoup de défauts de page :) Au contraire, si vous le faites de la "manière stupide" et que vous allouez beaucoup, beaucoup de mémoire, cela peut être incroyablement rapide. J'ai apprécié l'article du développeur danois de FreeBSD Poul-Henning Kamp à ce sujet : queue.acm.org/detail.cfm?id=1814327

22voto

Jarret Hardie Points 36266

Vous n'avez pas vraiment beaucoup d'options si les lignes sont de longueurs différentes... vous devez simplement traiter les caractères de fin de ligne pour savoir quand vous avez progressé vers la ligne suivante.

Vous pouvez cependant accélérer considérablement cette opération ET réduire l'utilisation de la mémoire en donnant au dernier paramètre de "open" une valeur différente de 0.

0 signifie que l'opération de lecture du fichier est sans tampon, ce qui est très lent et intensif pour le disque. 1 signifie que le fichier est mis en mémoire tampon, ce qui est une amélioration. Tout ce qui est supérieur à 1 (disons 8k c'est-à-dire : 8096, ou plus) lit des morceaux du fichier en mémoire. Vous y accédez toujours par for line in open(etc): mais python ne fait qu'un petit bout à la fois, jetant chaque morceau en mémoire tampon après son traitement.

6 votes

8K est 8192, peut-être vaut-il mieux écrire 8 << 10 pour être plus sûr. :)

0 votes

Savez-vous par hasard si la taille de la mémoire tampon est spécifiée en octets ? Quel est le format approprié ? Puis-je écrire '8k' ? Ou devrais-je écrire '8096' ?

1 votes

HAHAHA... On doit être vendredi... Je ne sais clairement pas faire de maths. La taille du buffer est bien un entier exprimant des octets, donc écrivez 8192 (pas 8096 :-) ), plutôt que 8

12voto

SilentGhost Points 79627

Je suis probablement gâté par une mémoire vive abondante, mais 15 M n'est pas énorme. Lire en mémoire avec readlines() est ce que je fais habituellement avec des fichiers de cette taille. Accéder à une ligne après cela est trivial.

0 votes

Pourquoi j'ai légèrement hésité à lire le fichier entier -- je pourrais avoir plusieurs de ces processus en cours d'exécution, et si une douzaine d'entre eux lisent 12 fichiers de 15MB chacun, cela pourrait ne pas être bon. Mais j'ai besoin de le tester pour savoir si ça va marcher. Merci.

4 votes

Hrm, et si c'est un fichier de 1GB ?

0 votes

@photographer : même "plusieurs" processus lisant des fichiers de 15MB ne devraient pas avoir d'importance sur une machine moderne typique (en fonction, bien sûr, de ce que vous faites exactement avec eux).

10voto

Joran Beasley Points 28451

Je suis surpris que personne n'ait mentionné Islice.

line = next(itertools.islice(Fhandle,index_of_interest,index_of_interest+1),None) # just the one line

ou si vous voulez tout le reste du fichier

rest_of_file = itertools.islice(Fhandle,index_of_interest)
for line in rest_of_file:
    print line

ou si vous voulez que toutes les autres lignes du fichier

rest_of_file = itertools.islice(Fhandle,index_of_interest,None,2)
for odd_line in rest_of_file:
    print odd_line

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X