Уведомления

Группа в Telegram: @pythonsu

#1 Ноя. 24, 2010 13:47:42

armir
От:
Зарегистрирован: 2010-11-24
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

Собственно столкнулся с сабжем. Для парсера нужно читать последнюю строку из файла, что бы можно было продолжить работу сто старого места. Файл большой 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



Офлайн

#2 Ноя. 24, 2010 16:03:44

Ferroman
От:
Зарегистрирован: 2006-11-16
Сообщения: 2759
Репутация: +  1  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

Вполне нормальный код. Думаю, достаточно будет сделать из него функцию.

Офлайн

#3 Ноя. 24, 2010 17:44:24

ofigetitelno
От:
Зарегистрирован: 2006-08-01
Сообщения: 136
Репутация: +  0  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

:)
Лучше читать блоками, а не по одному байту.
Зачем перечитывать строку, которую уже считал?
Вариации на тему:

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



Офлайн

#4 Ноя. 24, 2010 21:52:39

armir
От:
Зарегистрирован: 2010-11-24
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

ofigetitelno
:)
Лучше читать блоками, а не по одному байту.
Зачем перечитывать строку, которую уже считал?
Видел подобное решение (или такое же) в нете. Но у меня строки состоят из ‘nickname:id’, то есть небольшие; И считывать посимвольно - вполне себя окупает. Да и логика (имхо) попроще. Сначала сделал без повторного считывания всей строки. Каждый символ аппендил в список, а потом объединял его в строку, но было громоздко уж очень.
А с повторным считыванием вышло поменьше кода, но все равно как-то не очень элегантно:)



Офлайн

#5 Ноя. 25, 2010 13:11:25

Subideal Ox
От:
Зарегистрирован: 2010-11-23
Сообщения: 65
Репутация: +  0  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

Вот мой вариант. По-моему элегантно =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
PS Предыдущие свои сообщения удалил, чтобы не засорять эфир :)

SO



Отредактировано (Ноя. 25, 2010 13:18:50)

Офлайн

#6 Ноя. 26, 2010 01:57:37

pyuser
От:
Зарегистрирован: 2007-05-13
Сообщения: 658
Репутация: +  36  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

Subideal Ox
Вот мой вариант. По-моему элегантно
только первую строку файла возвращать не хочет :(



Офлайн

#7 Ноя. 26, 2010 08:59:53

Subideal Ox
От:
Зарегистрирован: 2010-11-23
Сообщения: 65
Репутация: +  0  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

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()



Офлайн

#8 Ноя. 26, 2010 17:38:03

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  252  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

Такая задача часто встречается во всяких логах. Файл длинный сообщений много, но их круг ограничен. Решить задачу значительно проще если сделать дополнительные предположения. В данном случае можно декларировать что длина строки не более 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]
кстати - все открывают файл в текстовом режиме - в доке написано: seek для текстовых файлов дает непредсказуемый результат.



Отредактировано (Ноя. 26, 2010 17:38:53)

Офлайн

#9 Ноя. 26, 2010 22:54:33

Subideal Ox
От:
Зарегистрирован: 2010-11-23
Сообщения: 65
Репутация: +  0  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

Из документации к 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



Офлайн

#10 Ноя. 26, 2010 23:06:52

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Быстрый способ прочитать последнюю строку в файле

Вывод неправильный.

Несмотря на то, что файл открыт в символьном режиме seek и tell оперируют байтовыми смещениями.

Рассмотрим следующую ситуацию: файл в utf-8 с русскими буквами и переводом строки в unix стиле.
В этом случае можно “прыгать” только на начала символов. Т.е. если содержимое файла начинается с

Русский файл
Вторая строка файла
то правильные позиции сначала будут четными. Затем идет ‘\n’ - 1 байт. И снова двухбайтные символы.

Попытка позиционироваться внутрь символа собьет к чертям все что можно - так делать нельзя.
И угадать в общем случае невозможно - как я показал выше, длина символа может меняться.
Поэтому прыгать можно только на ранее полученные позиции.

Именно об этом и говорит документация.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version