Есть ли способ прочитать файл в обратном порядке с помощью открытого с использованием Python - PullRequest
0 голосов
/ 26 апреля 2019

Я пытаюсь прочитать файл сервера file.out, но мне нужно прочитать только самые последние данные в диапазоне дат и времени.

Возможно ли обратное чтение файла, используя with open() с режимами (методами)?

Режим a + дает доступ к концу файла:

    ``a+''  Open for reading and writing.  The file is created if it does not
      exist. The stream is positioned at the end of the file. Subsequent writes
      to the file will always end up at the then current end of the file, 
      irrespective of any intervening fseek(3) or similar.

Есть ли способ использовать + или другие режимы (методы) для доступа к концу файла и чтения определенного диапазона?

Поскольку обычный режим r читает файл с начала

    with open('file.out','r') as file:

пытался использовать reversed()

    for line in reversed(list(open('file.out').readlines())):

но он не возвращает строки для меня.

Или есть другие способы отменить чтение файла ... help

EDIT

Что я получил так далеко:

import os
import time
from datetime import datetime as dt

start_0 = dt.strptime('2019-01-27','%Y-%m-%d')
stop_0 = dt.strptime('2019-01-27','%Y-%m-%d')
start_1 = dt.strptime('09:34:11.057','%H:%M:%S.%f')
stop_1 = dt.strptime('09:59:43.534','%H:%M:%S.%f')

os.system("touch temp_file.txt")
process_start = time.clock()
count = 0
print("reading data...")
for line in reversed(list(open('file.out'))):
    try:
        th = dt.strptime(line.split()[0],'%Y-%m-%d')
        tm = dt.strptime(line.split()[1],'%H:%M:%S.%f')

        if (th == start_0) and (th <= stop_0):
            if (tm > start_1) and (tm < stop_1):
                count += 1
                print("%d occurancies" % (count))
                os.system("echo '"+line.rstrip()+"' >> temp_file.txt")
        if (th == start_0) and (tm < start_1):
            break
    except KeyboardInterrupt:
        print("\nLast line before interrupt:%s" % (str(line)))
        break
    except IndexError as err:
        continue
    except ValueError as err:
        continue
process_finish = time.clock()
print("Done:" + str(process_finish - process_start) + " seconds.")

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

Проблема в том, что он читает, но слишком медленно ..

РЕДАКТИРОВАТЬ 2

(2019-04-29 9.34)

Все полученные мной ответы хорошо подходят для обратного чтения журналов, но в моем (и, возможно, для других) случае, когда у вас есть журнал размером n ГБ, ответ Рокки ниже мне подошел лучше всего.

Код, который работает для меня:

(я только добавил цикл для кода Рокки):

import collections

log_lines = collections.deque()
for line in open("file.out", "r"):
    log_lines.appendleft(line)
    if len(log_lines) > number_of_rows:
        log_lines.pop()

log_lines = list(log_lines)
for line in log_lines:
    print(str(line).split("\n"))

Спасибо людям, все ответы работают.

-lpkej

Ответы [ 4 ]

0 голосов
/ 26 апреля 2019

Эй, m8 Я сделал этот код, он работает для меня, я могу прочитать в моем файле в обратном порядке. Надеюсь, поможет :) Я начинаю с создания нового текстового файла, поэтому не знаю, насколько это важно для вас.

def main():
f = open("Textfile.txt", "w+")
for i in range(10):
    f.write("line number %d\r\n" % (i+1))

f.close
def readReversed():
for line in reversed(list(open("Textfile.txt"))):
    print(line.rstrip())

main()
readReversed()
0 голосов
/ 26 апреля 2019

Нет способа сделать это с open параметрами, но если вы хотите прочитать последнюю часть большого файла без загрузки этого файла в память (что и сделает reversed(list(fp))), вы можете использовать 2 прохода решение.

LINES_FROM_END = 1000
with open(FILEPATH, "r") as fin:
    s = 0
    while fin.readline(): # fixed typo, readlines() will read everything...
        s += 1
    fin.seek(0)
    mylines = []
    for i, e in enumerate(fin):
        if i >= s - LINES_FROM_END:
            mylines.append(e)

Это не сохранит ваш файл в памяти, вы также можете уменьшить его до одного прохода, используя collections.deque

# one pass (a lot faster):
mylines = collections.deque()
for line in open(FILEPATH, "r"):
    mylines.appendleft(line)
    if len(mylines) > LINES_FROM_END:
        mylines.pop()

mylines = list(mylines)
# mylines will contain #LINES_FROM_END count of lines from the end.
0 голосов
/ 26 апреля 2019

Другой вариант - mmap.mmap файл, а затем использовать rfind с конца для поиска newline s, а затем вырезать строки.

0 голосов
/ 26 апреля 2019

Конечно, есть:

filename = 'data.txt'
for line in reversed(list(open(filename))):
    print(line.rstrip())

РЕДАКТИРОВАТЬ: Как упоминалось в комментариях, это будет читать весь файл в память.Это решение не следует использовать с большими файлами.

...