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)

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top