Python, читающий только конец огромного текстового файла

Возможный дубликат:
Получить последние n строк файла с Python, похожие на хвост
Прочитайте файл в обратном порядке с помощью python

У меня есть файл размером около 15 ГБ, это файл журнала, из которого я должен анализировать вывод. Я уже делал базовый синтаксический анализ аналогичного, но БОЛЬШОГО меньшего файла, с несколькими строками ведения журнала. Строки анализа - это не проблема. Проблема заключается в огромном файле и количестве избыточных данных, которые он содержит.

В основном я пытаюсь сделать python script, что я могу сказать; например, дайте мне 5000 последних строк файла. Это опять-таки основная обработка аргументов и все такое, ничего особенного там, я могу это сделать.

Но как определить или сообщить читателю файла ТОЛЬКО прочитать количество строк, которые я указал в конце файла? Я пытаюсь пропустить huuuuuuuge количество строк в начале файла, так как я не заинтересован в этих и, честно говоря, чтение около 15 ГБ строк из txt файла занимает слишком много времени. Есть ли способ ошибиться. Начните читать с конца файла? Это даже имеет смысл?

Все сводится к проблеме чтения 15-гигабайтного файла, строка за строкой занимает слишком много времени. Поэтому я хочу пропустить уже избыточные данные (по крайней мере, избыточно для меня) и только читать количество строк из конца файла, который я хочу прочитать.

Очевидный ответ заключается в том, чтобы вручную просто скопировать N количество строк из файла в другой файл, но есть ли способ сделать это полуавтоматически, только чтобы прочитать N количество строк из конца файла с помощью python?

Ответ 1

Вам нужно найти конец файла, а затем прочитать фрагменты в блоках с конца, подсчитывая строки, пока не найдете достаточно строк для чтения строк n.

В принципе, вы повторно реализуете простую форму хвоста.

Вот немного слегка проверенный код, который делает именно это:

import os, errno

def lastlines(hugefile, n, bsize=2048):
    # get newlines type, open in universal mode to find it
    with open(hugefile, 'rU') as hfile:
        if not hfile.readline():
            return  # empty, no point
        sep = hfile.newlines  # After reading a line, python gives us this
    assert isinstance(sep, str), 'multiple newline types found, aborting'

    # find a suitable seek position in binary mode
    with open(hugefile, 'rb') as hfile:
        hfile.seek(0, os.SEEK_END)
        linecount = 0
        pos = 0

        while linecount <= n + 1:
            # read at least n lines + 1 more; we need to skip a partial line later on
            try:
                hfile.seek(-bsize, os.SEEK_CUR)           # go backwards
                linecount += hfile.read(bsize).count(sep) # count newlines
                hfile.seek(-bsize, os.SEEK_CUR)           # go back again
            except IOError, e:
                if e.errno == errno.EINVAL:
                    # Attempted to seek past the start, can't go further
                    bsize = hfile.tell()
                    hfile.seek(0, os.SEEK_SET)
                    linecount += hfile.read(bsize).count(sep)
                    break
                raise  # Some other I/O exception, re-raise
            pos = hfile.tell()

    # Re-open in text mode
    with open(hugefile, 'r') as hfile:
        hfile.seek(pos, os.SEEK_SET)  # our file position from above

        for line in hfile:
            # We've located n lines *or more*, so skip if needed
            if linecount > n:
                linecount -= 1
                continue
            # The rest we yield
            yield line

Ответ 2

Подтвердите это для unix:

import os
os.popen('tail -n 1000 filepath').read()

используйте subprocess.Popen вместо os.popen, если вам нужно иметь доступ к stderr (и некоторым другим функциям)

Ответ 3

Хотя я бы предпочел решение "хвост" - если вы знаете максимальное количество символов в строке, вы можете реализовать другое возможное решение, получив размер файла, откройте обработчик файла и используйте метод "искать" с помощью определенное количество символов, которое вы ищете.

Этот заключительный код должен выглядеть так: просто объясните, почему я также предпочитаю хвостовое решение:) goodluck!

MAX_CHARS_PER_LINE = 80
size_of_file = os.path.getsize('15gbfile.txt')
file_handler = file.open('15gbfile.txt', "rb")
seek_index = size_of_file - (number_of_requested_lines * MAX_CHARS_PER_LINE)
file_handler.seek(seek_index)
buffer = file_handler.read()

вы можете улучшить этот код, проанализировав новые строки буфера, который вы читаете. Удачи (и вы должны использовать хвостовое решение;-) Я уверен, что вы можете получить хвост для каждой ОС.

Ответ 4

Предпочтительным методом в этот момент было просто использовать хвост unix для задания и модифицировать питон для принятия ввода через вход std.

tail hugefile.txt -n1000 | python magic.py

Ничего сексуального, но по крайней мере он заботится о работе. Я обнаружил, что большой файл слишком большой нагрузки для обработки. По крайней мере, для моих навыков питона. Так что было намного проще просто добавить к нему щепотку магии nix, чтобы сократить размер файла. Хвост был для меня новым. Узнал что-то и выяснил другой способ снова использовать терминал в моих интересах. Всем спасибо.