Como chegar a linha de arquivo aberto atual em python?
-
05-07-2019 - |
Pergunta
Suponha que você abrir um arquivo, e fazer um algum lugar seek () no arquivo, como você sabe o arquivo linha atual?
(eu, pessoalmente resolvido com uma classe de arquivo ad-hoc que mapeia a posição para a linha procuram após a digitalização do arquivo, mas eu queria ver outras dicas e acrescentar a esta pergunta para stackoverflow, como eu não era capaz de encontrar o problema em qualquer lugar no google)
Solução
Aqui está como eu iria abordar o problema, usando tanto a preguiça possível:
from random import randint
from itertools import takewhile, islice
file = "/etc/passwd"
f = open(file, "r")
f.seek(randint(10,250))
pos = f.tell()
print "pos=%d" % pos
def countbytes(iterable):
bytes = 0
for item in iterable:
bytes += len(item)
yield bytes
print 1+len(list(takewhile(lambda x: x <= pos, countbytes(open(file, "r")))))
Para um pouco menos legível, mas muito mais preguiçoso abordagem, o uso enumerate
e dropwhile
:
from random import randint
from itertools import islice, dropwhile
file = "/etc/passwd"
f = open(file, "r")
f.seek(randint(10,250))
pos = f.tell()
print "pos=%d" % pos
def countbytes(iterable):
bytes = 0
for item in iterable:
bytes += len(item)
yield bytes
print list(
islice(
dropwhile(lambda x: x[1] <= pos, enumerate(countbytes(open(file, "r"))))
, 1))[0][0]+1
Outras dicas
Quando você usa seek (), python começa a usar offsets ponteiro para saltar para a posição desejada no arquivo. Mas, a fim de saber o número da linha atual, você tem que analisar cada personagem até essa posição. Então, assim como você pode abandonar seek () em favor da leitura ():
Substitua
f = open(filename, "r")
f.seek(55)
com
f = open(filename, "r")
line=f.read(55).count('\n')+1
print(line)
Talvez você não quiser usar f.read (num) uma vez que este pode exigir muita memória se num é muito grande. Nesse caso, você poderia usar um gerador de como este:
import itertools
import operator
line_number=reduce(operator.add,( f.read(1)=='\n' for _ in itertools.repeat(None,num)))
pos=f.tell()
Isto é equivalente a f.seek(num)
com o benefício adicional de dar-lhe line_number
.