Форум сайта python.su
Собственно столкнулся с сабжем. Для парсера нужно читать последнюю строку из файла, что бы можно было продолжить работу сто старого места. Файл большой 15 - 20 кк строк.
Дядя Гугл сказал, что встроенного метода решения проблемы - нет:
- Либо прочитать весь файл readlines и взять последнюю строку (быстро, но всю память съест ).
- Либо пробежать весь файл xreadlines и опять таки взять последнюю строку (память останется целой, но каждый раз ждать пока переберется весь файл).
Короче - не один вариант не подходит. Пришлось идти самым примитивным путем, перебирать каждый символ с конца файла и при совпадении его с символом конца строки - выводить. Но код у меня получился страшноватый:) Может кто подправит или расскажет как он делает?
myIter = 1
with open("myfile") as f:
while 1:
myIter += 1
f.seek(-myIter, 2)
sim = f.read(1)
if sim == u'\n':
res = f.readline().rstrip()
break
print res
Офлайн
Вполне нормальный код. Думаю, достаточно будет сделать из него функцию.
Офлайн
:)
Лучше читать блоками, а не по одному байту.
Зачем перечитывать строку, которую уже считал?
Вариации на тему:
s = ''
cur_block_size = block_size = 1024
with open('users.txt') as f:
while True:
f.seek(-1*cur_block_size, 2)
s = f.read(block_size) + s
res = s.split('\n')
if len(res) > 2:
print res[-2]
break
cur_block_size += block_size
Офлайн
ofigetitelnoВидел подобное решение (или такое же) в нете. Но у меня строки состоят из ‘nickname:id’, то есть небольшие; И считывать посимвольно - вполне себя окупает. Да и логика (имхо) попроще. Сначала сделал без повторного считывания всей строки. Каждый символ аппендил в список, а потом объединял его в строку, но было громоздко уж очень.
:)
Лучше читать блоками, а не по одному байту.
Зачем перечитывать строку, которую уже считал?
Офлайн
Вот мой вариант. По-моему элегантно =D
from itertools import repeat
def reverse_readline (f_path):
f = open(f_path, 'r')
f.seek(0, 2)
it = ( '' if f.tell() == 1 else (f.seek(-2, 1) or f.read(1)) for i in repeat(None))
while True:
st = ''
for ch in it:
if ch == '': raise StopIteration()
if ch == '\n': break
else: st = ch + st
yield st
Отредактировано (Ноя. 25, 2010 13:18:50)
Офлайн
Subideal Oxтолько первую строку файла возвращать не хочет :(
Вот мой вариант. По-моему элегантно
Офлайн
pyuserКаков подлец! =D Спасибо за замечание
только первую строку файла возвращать не хочет
def read_last(f_path):
f = open(f_path, 'r')
f.seek(0, 2)
it = ( '' if f.tell() == 1 else (f.seek(-2, 1) or f.read(1)) for i in repeat(None))
while True:
st = ''
for ch in it:
if ch == '\n' or not ch: break
else: st = ch + st
yield st
if not ch: raise StopIteration()
Офлайн
Такая задача часто встречается во всяких логах. Файл длинный сообщений много, но их круг ограничен. Решить задачу значительно проще если сделать дополнительные предположения. В данном случае можно декларировать что длина строки не более MAX_ROW. Тогда будет еще красивее и эффективнее
import os
def LastRow(fileName,MAX_ROW=200):
"""отдать последнюю строку файла"""
with open(fileName,"rb") as f:
f.seek(-min(os.path.getsize(fileName),MAX_ROW),2)
return (f.read().splitlines())[-1]
Отредактировано (Ноя. 26, 2010 17:38:53)
Офлайн
Из документации к seek: If the file is opened in text mode (without ‘b’), only offsets returned by tell() are legal. Use of other offsets causes undefined behavior.
Дословно: Если файл открыт в текстовом режиме (без ‘b’), правомерны только отступы, возвращаемые tell(). Использование прочих отступов вызывает неопределенное поведение.
Какая-то мутная фраза, но уж точно не эквивалентна seek для текстовых файлов дает непредсказуемый результат . Или у вас другой текст? Можно ссылку?
Смотрим tell: Return the file’s current position, like stdio‘s ftell().
Смотрим stdio‘s ftell() (в GNU libc): This function can fail if the stream doesn't support file positioning, or if the file position can't be represented in a long int, and possibly for other reasons as well. If a failure occurs, a value of -1 is returned.
Мой вывод: поведение не определено в случае, если отступ превышает long int в С-компиляторе, на котором собран Ваш python.
SO
Офлайн
Вывод неправильный.
Несмотря на то, что файл открыт в символьном режиме seek и tell оперируют байтовыми смещениями.
Рассмотрим следующую ситуацию: файл в utf-8 с русскими буквами и переводом строки в unix стиле.
В этом случае можно “прыгать” только на начала символов. Т.е. если содержимое файла начинается с
Русский файл
Вторая строка файла
Офлайн