Как получить текущую строку открытого файла в python?
-
05-07-2019 - |
Вопрос
Предположим, вы открываете файл и выполняете функцию seek() где-нибудь в файле, откуда вы знаете текущую строку файла?
(Я лично решил проблему с помощью специального файлового класса, который сопоставляет позицию поиска строке после сканирования файла, но я хотел увидеть другие подсказки и добавить этот вопрос в stackoverflow, поскольку я не смог найти проблему нигде в Google)
Решение
Вот как я мог бы подойти к проблеме, используя как можно больше лени:
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")))))
Для немного менее читабельного, но гораздо более ленивого подхода используйте enumerate
и drop while
:
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
Другие советы
Когда вы используете seek(), python получает возможность использовать смещения указателя для перехода к нужной позиции в файле.Но для того, чтобы узнать текущий номер строки, вы должны изучить каждый символ вплоть до этой позиции.Так что вы могли бы с таким же успехом отказаться от функции seek() в пользу функции read():
Заменить
f = open(filename, "r")
f.seek(55)
с
f = open(filename, "r")
line=f.read(55).count('\n')+1
print(line)
Возможно, вы не хотите использовать f.read(num), поскольку для этого может потребоваться много памяти, если num очень большой.В этом случае вы могли бы использовать такой генератор, как этот:
import itertools
import operator
line_number=reduce(operator.add,( f.read(1)=='\n' for _ in itertools.repeat(None,num)))
pos=f.tell()
Это эквивалентно f.seek(num)
с дополнительным преимуществом предоставления вам line_number
.