Мне нужно знать, как читать строки из файла в python, чтобы я сначала прочитал последнюю строку и продолжаю так, пока курсор не достигнет начала файла. Есть идеи?
Как читать строки из файла на питоне, начиная с конца
Ответ 1
Общий подход к этой проблеме, считывая текстовый файл в обратном порядке, по-разному, может быть решен, по крайней мере, тремя способами.
Общая проблема заключается в том, что, поскольку каждая строка может иметь разную длину, вы не можете заранее знать, где каждая строка начинается в файле, а также сколько из них есть. Это означает, что вам нужно применить некоторую логику к проблеме.
Общий подход # 1: чтение всего файла в память
При таком подходе вы просто читаете весь файл в памяти, в некоторой структуре данных, которая впоследствии позволяет обрабатывать список строк в обратном порядке. Это может быть стек, двусвязный список или даже массив.
Плюсы: Действительно легко реализовать (возможно, встроенный в Python для всех, кого я знаю)
Минусы: Использует много памяти, может потребоваться некоторое время для чтения больших файлов
Общий подход # 2: Прочитайте весь файл, сохраните позицию строк
При таком подходе вы также читаете весь файл один раз, но вместо хранения всего файла (всего текста) в памяти вы сохраняете только двоичные позиции внутри файла, где начиналась каждая строка. Вы можете сохранить эти позиции в аналогичной структуре данных, как та, которая хранит строки в первом подходе.
Вы хотите прочитать строку X, вам нужно перечитать строку из файла, начиная с позиции, которую вы сохранили для начала этой строки.
Плюсы: Почти так же легко реализовать как первый подход
Минусы: может потребоваться некоторое время для чтения больших файлов
Общий подход №3: Прочтите файл в обратном порядке и "выберите его"
При таком подходе вы будете читать фрагмент файла или аналогичный, с конца, и посмотреть, где находятся концы. У вас в основном есть буфер, скажем, 4096 байт, и обрабатывать последнюю строку этого буфера. Когда ваша обработка, которая должна перемещать одну строку за раз назад в этом буфере, подходит к началу буфера, вам нужно прочитать другую ценность данных в буфере, от области до первого прочитанного буфера и продолжить обработку.
Этот подход, как правило, более сложный, потому что вам нужно обрабатывать такие вещи, как линии, разбитые на два буфера, а длинные строки могут даже охватывать более двух буферов.
Это, однако, тот, который потребует наименьшего объема памяти и для действительно больших файлов, также может быть полезно сделать это, чтобы сначала не считывать гигабайты информации.
Плюсы: Использует небольшую память, не требует, чтобы вы сначала прочитали весь файл
Минусы: Многое трудно реализовать и получить право на все угловые случаи
В сети есть множество ссылок, в которых показано, как сделать третий подход:
Ответ 2
Ответ 3
Вы также можете использовать модуль 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
# do it again
for l in frb:
print l
Дополнительную документацию можно найти на http://file-read-backwards.readthedocs.io/en/latest/readme.html
Ответ 4
Прямым способом является создание временного файла с переворачиванием, а затем изменение каждой строки в этом файле.
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).
Ответ 5
Это решение проще, чем любые другие, которые я видел.
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)