web-dev-qa-db-fra.com

Python: annule une opération de fichier readline () afin que le pointeur de fichier retrouve son état d'origine

Je suis en train de parcourir un pointeur de fichier Python d'un fichier texte en mode lecture seule, en utilisant file.readline () à la recherche d'une ligne spéciale. Une fois que je trouve cette ligne, je veux passer le pointeur de fichier à une méthode qui attend du pointeur de fichier au début de cette ligne de lecture (pas juste après).

Comment puis-je essentiellement annuler une opération file.readline () sur un pointeur de fichier?

29
MikeN

Vous devez vous rappeler la position en appelant file.tell() avant la ligne de lecture, puis en appelant file.seek() pour revenir en arrière. Quelque chose comme:

fp = open('myfile')
last_pos = fp.tell()
line = fp.readline()
while line != '':
  if line == 'SPECIAL':
    fp.seek(last_pos)
    other_function(fp)
    break
  last_pos = fp.tell()
  line = fp.readline()

Je ne me souviens plus s'il est sûr d'appeler file.seek() à l'intérieur d'une boucle for line in file, aussi j'écris généralement la boucle while. Il y a probablement une manière beaucoup plus pythonique de le faire.

42
D.Shawley

Vous enregistrez le point de départ de la ligne avec thefile.tell() avant d'appeler readline et vous revenez à ce point, si nécessaire, avec thefile.seek.

>>> with open('bah.txt', 'w') as f:
...   f.writelines('Hello %s\n' % i for i in range(5))
... 
>>> with open('bah.txt') as f:
...   f.readline()
...   x = f.tell()
...   f.readline()
...   f.seek(x)
...   f.readline()
... 
'Hello 0\n'
'Hello 1\n'
'Hello 1\n'
>>> 

comme vous le voyez, le "couple" cherche/dit est "défait", pour ainsi dire, le mouvement du pointeur de fichier effectué par readline. Bien sûr, cela ne peut fonctionner que sur un fichier réel à rechercher (disque), pas (par exemple) sur des objets de type fichier construits avec la méthode makefile de sockets, etc.

11
Alex Martelli

Si votre méthode veut simplement parcourir le fichier, vous pouvez utiliser itertools.chain pour créer un itérateur approprié:

import itertools

def process(it):
    for line in it:
        print line,

with open(filename,'r') as f:
    for line in f:
        if 'marker' in line:
            it=itertools.chain((line,),f)
            process(it)
            break
3
unutbu
fin = open('myfile')
for l in fin:
    if l == 'myspecialline':
        # Move the pointer back to the beginning of this line
        fin.seek(fin.tell() - len(l))
        break
# now fin points to the start of your special line
1
GWW

Si vous ne connaissez pas la dernière ligne parce que vous ne l'avez pas visitée, vous pouvez lire à l'envers jusqu'à ce que vous voyiez un caractère de nouvelle ligne:

with open(logfile, 'r') as f:
    # go to EOF
    f.seek(0, os.SEEK_END)
    nlines = f.tell()
    i=0
    while True:
        f.seek(nlines-i)
        char = f.read(1)
        if char=='\n':
            break
        i+=1
0
JLT