Какой-нибудь способ читать текстовые файлы в обратном порядке, строка за строкой? - PullRequest
0 голосов
/ 28 февраля 2019

Я хочу прочитать текстовый файл, приведенный ниже, в обратном направлении строка за строкой.Я не хочу использовать readlines() или read().

a.txt

2018/03/25-00:08:48.638553  508     7FF4A8F3D704     snononsonfvnosnovoosr
2018/03/25-10:08:48.985053 346K     7FE9D2D51706     ahelooa afoaona woom
2018/03/25-20:08:50.486601 1.5M     7FE9D3D41706     qojfcmqcacaeia
2018/03/25-24:08:50.980519  16K     7FE9BD1AF707     user: number is 93823004
2018/03/26-00:08:50.981908 1389     7FE9BDC2B707     user 7fb31ecfa700
2018/03/26-10:08:51.066967    0     7FE9BDC91700     Exit Status = 0x0
2018/03/26-15:08:51.066968    1     7FE9BDC91700     std:ZMD:

ожидаемый результат:

2018/03/26-15:08:51.066968    1     7FE9BDC91700     std:ZMD:
2018/03/26-10:08:51.066967    0     7FE9BDC91700     Exit Status = 0x0
2018/03/26-00:08:50.981908 1389     7FE9BDC2B707     user 7fb31ecfa700
2018/03/25-24:08:50.980519  16K     7FE9BD1AF707     user: number is 93823004
2018/03/25-20:08:50.486601 1.5M     7FE9D3D41706     qojfcmqcacaeia
2018/03/25-10:08:48.985053 346K     7FE9D2D51706     ahelooa afoaona woom
2018/03/25-00:08:48.638553  508     7FF4A8F3D704     snononsonfvnosnovoosr

Мое решение:

with open('a.txt') as lines:
    for line in reversed(lines):
        print(line)

Ответы [ 3 ]

0 голосов
/ 28 февраля 2019

Вот способ сделать это, не считывая весь файл в память сразу.Для этого требуется сначала прочитать весь файл, но сохранить только там, где начинается каждая строка.Как только это станет известно, он может использовать метод seek() для случайного доступа к каждому из них в любом порядке.

Вот пример использования входного файла:

# Preprocess - read whole file and note where lines start.
# (Needs to be done in binary mode.)
with open('text_file.txt', 'rb') as file:
    offsets = [0]  # First line is always at offset 0.
    for line in file:
        offsets.append(file.tell())  # Append where *next* line would start.

# Now reread lines in file in reverse order.
with open('text_file.txt', 'rb') as file:
    for index in reversed(range(len(offsets)-1)):
        file.seek(offsets[index])
        size = offsets[index+1] - offsets[index]  # Difference with next.
        # Read bytes, convert them to a string, and remove whitespace at end.
        line = file.read(size).decode().rstrip()
        print(line)

Вывод:

2018/03/26-15:08:51.066968    1     7FE9BDC91700     std:ZMD:
2018/03/26-10:08:51.066967    0     7FE9BDC91700     Exit Status = 0x0
2018/03/26-00:08:50.981908 1389     7FE9BDC2B707     user 7fb31ecfa700
2018/03/25-24:08:50.980519  16K     7FE9BD1AF707     user: number is 93823004
2018/03/25-20:08:50.486601 1.5M     7FE9D3D41706     qojfcmqcacaeia
2018/03/25-10:08:48.985053 346K     7FE9D2D51706     ahelooa afoaona woom
2018/03/25-00:08:48.638553  508     7FF4A8F3D704     snononsonfvnosnovoosr

Обновление

Вот версия, которая делает то же самое, но использует модуль Python mmap для карта памяти файл, который должен обеспечить лучшую производительность, используя возможности виртуальной памяти вашей ОС / оборудования.

Это потому, что, как выразился PyMOTW-3 :

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

Код:

import mmap

with open('text_file.txt', 'rb') as file:
    with mmap.mmap(file.fileno(), length=0, access=mmap.ACCESS_READ) as mm_file:

        # First preprocess the file and note where lines start.
        # (Needs to be done in binary mode.)
        offsets = [0]  # First line is always at offset 0.
        for line in iter(mm_file.readline, b""):
            offsets.append(mm_file.tell())  # Append where *next* line would start.

        # Now process the lines in file in reverse order.
        for index in reversed(range(len(offsets)-1)):
            mm_file.seek(offsets[index])
            size = offsets[index+1] - offsets[index]  # Difference with next.
            # Read bytes, convert them to a string, and remove whitespace at end.
            line = mm_file.read(size).decode().rstrip()
            print(line)
0 голосов
/ 01 марта 2019

Решение Whlie @ martineau выполняет работу без загрузки всего файла в память, тем не менее, оно расточительно читает весь файл дважды.

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

class ReversedTextReader:
    def __init__(self, file, chunk_size=50):
        self.file = file
        file.seek(0, 2)
        self.position = file.tell()
        self.chunk_size = chunk_size
        self.buffer = ''

    def __iter__(self):
        return self

    def __next__(self):
        if not self.position and not self.buffer:
            raise StopIteration
        chunk = self.buffer
        while True:
            line_start = chunk.rfind('\n', 0, len(chunk) - 1 - (chunk is self.buffer))
            if line_start != -1:
                break
            chunk_size = min(self.chunk_size, self.position)
            self.position -= chunk_size
            self.file.seek(self.position)
            chunk = self.file.read(chunk_size)
            if not chunk:
                line = self.buffer
                self.buffer = ''
                return line
            self.buffer = chunk + self.buffer
        line_start += 1
        line = self.buffer[line_start:]
        self.buffer = self.buffer[:line_start]
        return line

, чтобы:

from io import StringIO

f = StringIO('''2018/03/25-00:08:48.638553  508     7FF4A8F3D704     snononsonfvnosnovoosr
2018/03/25-10:08:48.985053 346K     7FE9D2D51706     ahelooa afoaona woom
2018/03/25-20:08:50.486601 1.5M     7FE9D3D41706     qojfcmqcacaeia
2018/03/25-24:08:50.980519  16K     7FE9BD1AF707     user: number is 93823004
2018/03/26-00:08:50.981908 1389     7FE9BDC2B707     user 7fb31ecfa700
2018/03/26-10:08:51.066967    0     7FE9BDC91700     Exit Status = 0x0
2018/03/26-15:08:51.066968    1     7FE9BDC91700     std:ZMD:
''')

for line in ReversedTextReader(f):
    print(line, end='')

вывод:

2018/03/26-15:08:51.066968    1     7FE9BDC91700     std:ZMD:
2018/03/26-10:08:51.066967    0     7FE9BDC91700     Exit Status = 0x0
2018/03/26-00:08:50.981908 1389     7FE9BDC2B707     user 7fb31ecfa700
2018/03/25-24:08:50.980519  16K     7FE9BD1AF707     user: number is 93823004
2018/03/25-20:08:50.486601 1.5M     7FE9D3D41706     qojfcmqcacaeia
2018/03/25-10:08:48.985053 346K     7FE9D2D51706     ahelooa afoaona woom
2018/03/25-00:08:48.638553  508     7FF4A8F3D704     snononsonfvnosnovoosr
0 голосов
/ 28 февраля 2019

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

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

Интерфейс file читаеттолько в одном направлении.Вы можете seek() перейти в другое место, но стандартные операции ввода-вывода работают только с увеличением описаний местоположений.

Чтобы ваше решение работало, вам нужно прочитать весь файл - вы можете 't reverse неявный итератор дескриптора файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...