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...

3voto

kamathln Points 51

Qu'est-ce qui génère le fichier que vous voulez traiter ? Si vous pouvez le contrôler, vous pouvez générer un index (quelle ligne se trouve à quelle position) au moment où le fichier est ajouté. Le fichier d'index peut être d'une taille de ligne fixe (chiffres avec espace ou avec 0) et sera certainement plus petit. Il peut donc être lu et traité rapidement.

  • Quelle ligne voulez-vous ?.
  • Calculer le décalage d'octet du numéro de ligne correspondant dans le fichier d'index (possible car la taille de ligne du fichier d'index est constante).
  • Utilisez seek ou autre pour sauter directement à la ligne du fichier d'index.
  • Analyse pour obtenir le décalage d'octet pour la ligne correspondante du fichier actuel.

3voto

user3810114 Points 11

J'ai eu le même problème (besoin d'extraire une ligne spécifique d'un énorme fichier).

Bien sûr, je peux à chaque fois parcourir tous les enregistrements du fichier et l'arrêter lorsque le compteur est égal à la ligne cible, mais cela ne fonctionne pas efficacement dans le cas où vous voulez obtenir plusieurs lignes spécifiques. C'est la raison pour laquelle le problème principal à résoudre est le suivant : comment gérer directement l'endroit nécessaire du fichier.

J'ai trouvé la décision suivante : Tout d'abord, j'ai complété le dictionnaire avec la position de départ de chaque ligne (la clé est le numéro de ligne, et la valeur - la longueur cumulée des lignes précédentes).

t = open(file,’r’)
dict_pos = {}

kolvo = 0
length = 0
for each in t:
    dict_pos[kolvo] = length
    length = length+len(each)
    kolvo = kolvo+1

en fin de compte, la fonction d'objectif :

def give_line(line_number):
    t.seek(dict_pos.get(line_number))
    line = t.readline()
    return line

t.seek(line_number) - commande qui exécute l'élagage du fichier jusqu'à la ligne initiale. Ainsi, si vous commettez ensuite readline - vous obtenez votre ligne cible.

En utilisant cette approche, j'ai gagné beaucoup de temps.

2voto

DNS Points 17577

Les lignes elles-mêmes contiennent-elles des informations sur l'indice ? Si le contenu de chaque ligne était quelque chose comme " <line index>:Data ", alors le seek() pourrait être utilisée pour effectuer une recherche binaire dans le fichier, même si la quantité d'information est trop importante. Data est variable. Il faut chercher au milieu du fichier, lire une ligne, vérifier si son indice est supérieur ou inférieur à celui que l'on veut, etc.

Sinon, le mieux que vous puissiez faire est de readlines() . Si vous ne voulez pas lire tous les 15MB, vous pouvez utiliser la fonction sizehint argument pour au moins remplacer un grand nombre de readline() avec un nombre plus faible d'appels à readlines() .

2voto

HongKun Yoo Points 363

Si vous avez affaire à un fichier de texte & sur la base de système linux vous pouvez utiliser les commandes linux.
Pour moi, cela a bien fonctionné !

import commands

def read_line(path, line=1):
    return commands.getoutput('head -%s %s | tail -1' % (line, path))

line_to_jump = 141978
read_line("path_to_large_text_file", line_to_jump)

0 votes

Bien sûr, il n'est pas compatible avec Windows ou certains types de shells linux qui ne supportent pas head / tail.

0 votes

Est-ce plus rapide que de le faire en Python ?

0 votes

Peut-on avoir plusieurs lignes ?

1voto

Andrew Dalke Points 7607

Voici un exemple d'utilisation de 'readlines(sizehint)' pour lire une partie des lignes à la fois. DNS m'a signalé cette solution. J'ai écrit cet exemple parce que les autres exemples ici sont orientés vers les lignes uniques.

def getlineno(filename, lineno):
    if lineno < 1:
        raise TypeError("First line is line 1")
    f = open(filename)
    lines_read = 0
    while 1:
        lines = f.readlines(100000)
        if not lines:
            return None
        if lines_read + len(lines) >= lineno:
            return lines[lineno-lines_read-1]
        lines_read += len(lines)

print getlineno("nci_09425001_09450000.smi", 12000)

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