Как читать строки из файла в Python, начиная с конца - PullRequest
12 голосов
/ 25 августа 2010

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

Ответы [ 5 ]

23 голосов
/ 25 августа 2010

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

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

Общий подход # 1: Читать весь файл в память

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

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

Общий подход # 2: Прочитать весь файл, сохранить положение строк

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

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

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

Общий подход № 3: прочитать файл в обратном порядке и «разобраться»

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

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

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

Плюсы: Использует мало памяти, не требует, чтобы вы сначала прочитали весь файл
Минусы: Сложно реализовать и получить право на все угловые случаи


В сети есть множество ссылок, которыепоказывает, как сделать третий подход:

4 голосов
/ 12 января 2017

Вы также можете использовать модуль Python file_read_backwards. Это будет прочитано эффективным способом памяти. Работает с Python 2.7 и 3.

Поддерживает кодировку utf-8, latin-1 и ascii. Он будет работать с "\ r", "\ n" и "\ r \ n" как с новыми строками.

После его установки через pip install file_read_backwards (v1.2.1) вы можете прочитать весь файл в обратном направлении (по строкам) с помощью:

#!/usr/bin/env python2.7

from file_read_backwards import FileReadBackwards

with FileReadBackwards("/path/to/file", encoding="utf-8") as frb:
    for l in frb:
         print l

Дополнительную документацию можно найти по адресу http://file -read-backwards.readthedocs.io / en / latest / readme.html

3 голосов
1 голос
/ 13 июня 2016

Это решение проще, чем любые другие, которые я видел.

def xreadlines_reverse(f, blksz=524288):
    "Act as a generator to return the lines in file f in reverse order."
    buf = ""
    f.seek(0, 2)
    pos = f.tell()
    lastn = 0
    if pos == 0:
        pos = -1
    while pos != -1:
        nlpos = buf.rfind("\n", 0, -1)
        if nlpos != -1:
            line = buf[nlpos + 1:]
            if line[-1] != "\n":
                line += "\n"
            buf = buf[:nlpos + 1]
            yield line
        elif pos == 0:
            pos = -1
            yield buf
        else:
            n = min(blksz, pos)
            f.seek(-(n + lastn), 1)
            rdbuf = f.read(n)
            lastn = len(rdbuf)
            buf = rdbuf + buf
            pos -= n

Пример использования:

for line in xreadlines_reverse(open("whatever.txt")):
    do_stuff(line)
1 голос
/ 28 марта 2011

Простой способ - сначала создать временный перевернутый файл, а затем перевернуть каждую строку в этом файле.

import os, tempfile

def reverse_file(in_filename, fout, blocksize=1024):
    filesize = os.path.getsize(in_filename)
    fin = open(in_filename, 'rb')
    for i in range(filesize // blocksize, -1, -1):
        fin.seek(i * blocksize)
        data = fin.read(blocksize)
        fout.write(data[::-1])

def enumerate_reverse_lines(in_filename, blocksize=1024):
    fout = tempfile.TemporaryFile()
    reverse_file(in_filename, fout, blocksize=blocksize)
    fout.seek(0)
    for line in fout:
        yield line[::-1]

Приведенный выше код выдаст строки с символами новой строки в начале, а не в конце, и нет никаких попыток обработать символы новой строки в стиле DOS / Windows (\ r \ n).

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