Я пишу средство просмотра файла журнала для веб-приложения, и для этого я хочу разбить на страницы строки файла журнала. Элементы в файле являются строками, основанными на самом новом элементе внизу.
Поэтому мне нужен tail()
метод, который может читать n
строки снизу и поддерживает смещение. То, что я придумал, выглядит так:
def tail(f, n, offset=0):
"""Reads a n lines from f with an offset of offset lines."""
avg_line_length = 74
to_read = n + offset
while 1:
try:
f.seek(-(avg_line_length * to_read), 2)
except IOError:
# woops. apparently file is smaller than what we want
# to step back, go to the beginning instead
f.seek(0)
pos = f.tell()
lines = f.read().splitlines()
if len(lines) >= to_read or pos == 0:
return lines[-to_read:offset and -offset or None]
avg_line_length *= 1.3
Это разумный подход? Каков рекомендуемый способ привязки лог-файлов к смещению?
seek(0,2)
затемtell()
), и использую это значение для поиска относительно начала.open
команды , используемой для созданияf
объекта файла должен быть указан, так как в зависимости от тогоf=open(..., 'rb')
или должны быть обработаны по- другомуf=open(..., 'rt')
f
Ответы:
Это может быть быстрее, чем у вас. Не делает никаких предположений о длине линии. Выполняется обратный просмотр файла по одному блоку за раз, пока не будет найдено правильное количество символов \ n.
Мне не нравятся хитрые предположения о длине линии, когда - с практической точки зрения - вы никогда не узнаете такие вещи.
Как правило, это позволит найти последние 20 строк на первом или втором проходе цикла. Если ваша 74-символьная вещь на самом деле точна, вы сделаете блок размером 2048, и вы почти сразу получите 20 строк.
Кроме того, я не сжигаю много мозговых калорий, пытаясь выровнять соответствие с физическими блоками ОС. Используя эти высокоуровневые пакеты ввода / вывода, я сомневаюсь, что вы увидите какие-либо последствия для производительности при попытке выравнивания по границам блоков ОС. Если вы используете низкоуровневый ввод-вывод, вы можете увидеть ускорение.
ОБНОВИТЬ
для Python 3.2 и выше, следуйте процессу на байтах, как в текстовых файлах (те, которые открыты без «b» в строке режима), разрешен только поиск относительно начала файла (исключение - поиск до самого конца файла с поиском (0, 2)) .:
например:
f = open('C:/.../../apache_logs.txt', 'rb')
источник
io.UnsupportedOperation: can't do nonzero end-relative seeks
я могу изменить смещение на 0, но это противоречит цели функции.Предполагается Unix-подобная система на Python 2, которую вы можете сделать:
Для Python 3 вы можете сделать:
источник
offset_total = str(n+offset)
и заменить эту строку,stdin,stdout = os.popen2("tail -n "+offset_total+" "+f)
чтобы избежатьTypeErrors (cannot concatenate int+str)
Вот мой ответ. Чистый питон. Использование timeit кажется довольно быстрым. Хвост 100 строк файла журнала, который имеет 100 000 строк:
Вот код:
источник
if len(lines_found) > lines:
действительно необходимо? Развеloop
условие не поймает это также?os.SEEK_END
используется просто для ясности? Насколько я нашел, его значение является постоянным (= 2). Я задавался вопросом о том, чтобы оставить это, чтобы иметь возможность оставить внеimport os
. Спасибо за отличное решение!os.SEEK_END
его целочисленным эквивалентом. Это было главным образом для удобочитаемости.while len(lines_found) < lines
чтобыwhile len(lines_found) <= lines
в моей копии. Спасибо!Если чтение всего файла приемлемо, тогда используйте deque.
До 2.6 у deques не было опции maxlen, но это достаточно легко реализовать.
Если необходимо прочитать файл с конца, используйте галопный поиск (он же экспоненциальный).
источник
pos *= 2
кажется совершенно произвольным. Каково его значение?Ответ С.Лотта выше почти работает для меня, но в итоге дает мне частичные строки. Оказывается, это повреждает данные на границах блоков, потому что данные хранят прочитанные блоки в обратном порядке. Когда вызывается '' .join (данные), блоки расположены в неправильном порядке. Это исправляет это.
источник
Код, который я в итоге использовал. Я думаю, что это пока лучшее
источник
Простое и быстрое решение с помощью mmap:
источник
.rfind
метод для сканирования в обратном порядке на наличие новых строк, вместо того, чтобы выполнять проверку байтов за раз на уровне Python; в CPython, заменяя код уровня Python на C встроенными звонками обычно много выигрывает). Для небольших входов,deque
сmaxlen
проще и, вероятно, так же быстро.Еще более чистая версия, совместимая с python3, которая не вставляет, а добавляет и переворачивает:
используйте это так:
источник
Обновите решение @papercrane до python3. Откройте файл с помощью
open(filename, 'rb')
и:источник
Отправка ответа по указанию комментаторов на мой ответ на аналогичный вопрос котором использовалась та же техника для изменения последней строки файла, а не просто для его получения.
Для файла значительного размера
mmap
это лучший способ сделать это. Чтобы улучшить существующийmmap
ответ, эта версия переносима между Windows и Linux и должна работать быстрее (хотя она не будет работать без некоторых модификаций 32-битного Python с файлами в диапазоне ГБ, см. Другой ответ для подсказок по обработке этой проблемы). и для модификации для работы на Python 2 ).Предполагается, что число выровненных строк достаточно мало, и вы можете безопасно прочитать их все в память одновременно; Вы также можете сделать это функцией генератора и вручную прочитать строку за раз, заменив последнюю строку на:
Наконец, это чтение в двоичном режиме (необходимо использовать
mmap
), так что он даетstr
строки (Py2) иbytes
строки (Py3); если вы хотитеunicode
(Py2) илиstr
(Py3), итеративный подход может быть настроен для декодирования для вас и / или исправления новых строк:Примечание: я напечатал все это на машине, где у меня нет доступа к Python для тестирования. Пожалуйста, дайте мне знать, если я что-то опечатал; это было достаточно похоже на мой другой ответ, что я думаю, что это должно работать, но изменения (например, обработка
offset
) могут привести к незначительным ошибкам. Пожалуйста, дайте мне знать в комментариях, если есть какие-либо ошибки.источник
Я нашел Popen выше, чтобы быть лучшим решением. Это быстро и грязно, и это работает Для Python 2.6 на Unix-машине я использовал следующее
soutput будет содержать последние n строк кода. Чтобы перебрать soutput построчно, выполните:
источник
основано на топовом ответе С. Лотта (25 сентября 2008 г. в 21:43), но исправлено для небольших файлов.
Надеюсь, это полезно.
источник
Существует несколько существующих реализаций tail на pypi, которые вы можете установить с помощью pip:
В зависимости от вашей ситуации могут быть преимущества использования одного из этих существующих инструментов.
источник
tailhead
,tailer
но они не работали. Также попробовалmtFileUtil
. Первоначально он выдавал ошибку, потому чтоprint
операторы не имели круглых скобок (я на Python 3.6). Я добавил их,reverse.py
и сообщения об ошибках исчезли, но когда мой скрипт вызывает модуль (mtFileUtil.tail(open(logfile_path), 5)
), он ничего не печатает.Просто :
источник
Для повышения эффективности работы с очень большими файлами (что часто встречается в файлах журналов, где вы можете использовать tail), вы, как правило, хотите избегать чтения всего файла (даже если вы делаете это, не считывая весь файл сразу в память). Однако вы делаете нужно как-то отработать смещение в строках, а не в символах. Одной из возможностей является чтение в обратном порядке с помощью функции seek () char за char, но это очень медленно. Вместо этого лучше обрабатывать большими блоками.
У меня есть служебная функция, которую я написал некоторое время назад для чтения файлов назад, которую можно использовать здесь.
[Редактировать] Добавлена более конкретная версия (избегать необходимости реверса дважды)
источник
вы можете перейти к концу вашего файла с помощью f.seek (0, 2), а затем прочитать строки одну за другой со следующей заменой readline ():
источник
Основано на ответе Eyecue (10 июня 2010 в 21:28): этот класс добавляет метод head () и tail () к объекту файла.
Использование:
источник
Некоторые из этих решений имеют проблемы, если файл не заканчивается на \ n или гарантирует, что вся первая строка будет прочитана.
источник
Вот довольно простая реализация:
источник
f.seek
? Почему не до тогоwith open
? Кроме того, почемуexcept
вы делаетеf.readlines()
?Есть очень полезный модуль, который может сделать это:
источник
Другое решение
если ваш текстовый файл выглядит так: мышь змея кошка ящерица волк собака
вы можете перевернуть этот файл, просто используя индексирование массива в python '' '
результат: собака волк ящерица кот
источник
Самый простой способ - использовать
deque
:источник
Мне пришлось прочитать определенное значение из последней строки файла, и наткнулся на этот поток. Вместо того, чтобы заново изобретать колесо в Python, я закончил крошечным сценарием оболочки, сохраненным как / usr / local / bin / get_last_netp:
И в программе Python:
источник
Не первый пример использования deque, но более простой. Это общее правило: оно работает с любым повторяемым объектом, а не только с файлом.
источник
источник
источник
источник
источник
Обновление для ответа, данного A.Coady
Работает с питоном 3 .
Это использует Экспоненциальный поиск и будет буферизовать только
N
строки сзади и очень эффективно.источник
Если подумать, это, вероятно, так же быстро, как и все здесь.
Это намного проще. И это, кажется, рвется в хорошем темпе.
источник