Odczyt pliku w odwrotnej kolejności za pomocą Pythona
Jak odczytać plik w odwrotnej kolejności za pomocą Pythona? Chcę przeczytać plik od ostatniej linii do pierwszej linii.
15 answers
for line in reversed(open("filename").readlines()):
print line.rstrip()
I w Pythonie 3:
for line in reversed(list(open("filename"))):
print(line.rstrip())
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-07 03:24:21
Poprawna, skuteczna odpowiedź napisana jako generator.
import os
def reverse_readline(filename, buf_size=8192):
"""a generator that returns the lines of a file in reverse order"""
with open(filename) as fh:
segment = None
offset = 0
fh.seek(0, os.SEEK_END)
file_size = remaining_size = fh.tell()
while remaining_size > 0:
offset = min(file_size, offset + buf_size)
fh.seek(file_size - offset)
buffer = fh.read(min(remaining_size, buf_size))
remaining_size -= buf_size
lines = buffer.split('\n')
# the first line of the buffer is probably not a complete line so
# we'll save it and append it to the last line of the next buffer
# we read
if segment is not None:
# if the previous chunk starts right from the beginning of line
# do not concact the segment to the last line of new chunk
# instead, yield the segment first
if buffer[-1] is not '\n':
lines[-1] += segment
else:
yield segment
segment = lines[0]
for index in range(len(lines) - 1, 0, -1):
if len(lines[index]):
yield lines[index]
# Don't yield None if the file was empty
if segment is not None:
yield segment
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-17 08:35:08
A może coś takiego:
import os
def readlines_reverse(filename):
with open(filename) as qfile:
qfile.seek(0, os.SEEK_END)
position = qfile.tell()
line = ''
while position >= 0:
qfile.seek(position)
next_char = qfile.read(1)
if next_char == "\n":
yield line[::-1]
line = ''
else:
line += next_char
position -= 1
yield line[::-1]
if __name__ == '__main__':
for qline in readlines_reverse(raw_input()):
print qline
Ponieważ plik jest odczytywany znak po znaku w odwrotnej kolejności, będzie działał nawet na bardzo dużych plikach, o ile poszczególne linie mieszczą się w pamięci.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-05 01:09:22
Możesz również użyć modułu Pythona file_read_backwards
.
Po zainstalowaniu, poprzez pip install file_read_backwards
(v1.2.1), Możesz odczytać cały plik wstecz (pod względem liniowym) w pamięci efektywny sposób poprzez:
#!/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
Obsługuje kodowanie"utf-8"," latin-1 "i" ascii".
Wsparcie jest również dostępne dla python3. Dalsze dokumenty można znaleźć na stronie http://file-read-backwards.readthedocs.io/en/latest/readme.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-28 02:06:47
for line in reversed(open("file").readlines()):
print line.rstrip()
Jeśli korzystasz z Linuksa, możesz użyć komendy tac
.
$ tac file
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-20 11:11:00
import re
def filerev(somefile, buffer=0x20000):
somefile.seek(0, os.SEEK_END)
size = somefile.tell()
lines = ['']
rem = size % buffer
pos = max(0, (size // buffer - 1) * buffer)
while pos >= 0:
somefile.seek(pos, os.SEEK_SET)
data = somefile.read(rem + buffer) + lines[0]
rem = 0
lines = re.findall('[^\n]*\n?', data)
ix = len(lines) - 2
while ix > 0:
yield lines[ix]
ix -= 1
pos -= buffer
else:
yield lines[0]
with open(sys.argv[1], 'r') as f:
for line in filerev(f):
sys.stdout.write(line)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-07 02:20:59
Tutaj znajdziesz moją implementację, możesz ograniczyć użycie pamięci ram zmieniając zmienną "buffer", jest błąd, że program wypisuje pustą linię na początku.
A także użycie pamięci ram może być zwiększone, jeśli nie ma nowych linii na więcej niż bajty bufora, zmienna" leak " będzie wzrastać aż do zobaczenia nowej linii ("\n").
To działa również dla plików 16 GB, które są większe niż moja całkowita pamięć.
import os,sys
buffer = 1024*1024 # 1MB
f = open(sys.argv[1])
f.seek(0, os.SEEK_END)
filesize = f.tell()
division, remainder = divmod(filesize, buffer)
line_leak=''
for chunk_counter in range(1,division + 2):
if division - chunk_counter < 0:
f.seek(0, os.SEEK_SET)
chunk = f.read(remainder)
elif division - chunk_counter >= 0:
f.seek(-(buffer*chunk_counter), os.SEEK_END)
chunk = f.read(buffer)
chunk_lines_reversed = list(reversed(chunk.split('\n')))
if line_leak: # add line_leak from previous chunk to beginning
chunk_lines_reversed[0] += line_leak
# after reversed, save the leakedline for next chunk iteration
line_leak = chunk_lines_reversed.pop()
if chunk_lines_reversed:
print "\n".join(chunk_lines_reversed)
# print the last leaked line
if division - chunk_counter < 0:
print line_leak
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-27 18:01:17
Dzięki za odpowiedź @srohde. Ma mały błąd sprawdzania znaku nowej linii z operatorem 'is', I nie mogłem skomentować odpowiedzi z reputacją 1. Również chciałbym zarządzać plikami otwartymi na zewnątrz, ponieważ umożliwia mi to osadzanie moich bełkotów w zadaniach luigi.
To, co musiałem zmienić, ma postać:
with open(filename) as fp:
for line in fp:
#print line, # contains new line
print '>{}<'.format(line)
Chciałbym zmienić na:
with open(filename) as fp:
for line in reversed_fp_iter(fp, 4):
#print line, # contains new line
print '>{}<'.format(line)
Tutaj jest zmodyfikowana odpowiedź, która chce obsługi pliku i zachowuje nowe linie:
def reversed_fp_iter(fp, buf_size=8192):
"""a generator that returns the lines of a file in reverse order
ref: https://stackoverflow.com/a/23646049/8776239
"""
segment = None # holds possible incomplete segment at the beginning of the buffer
offset = 0
fp.seek(0, os.SEEK_END)
file_size = remaining_size = fp.tell()
while remaining_size > 0:
offset = min(file_size, offset + buf_size)
fp.seek(file_size - offset)
buffer = fp.read(min(remaining_size, buf_size))
remaining_size -= buf_size
lines = buffer.splitlines(True)
# the first line of the buffer is probably not a complete line so
# we'll save it and append it to the last line of the next buffer
# we read
if segment is not None:
# if the previous chunk starts right from the beginning of line
# do not concat the segment to the last line of new chunk
# instead, yield the segment first
if buffer[-1] == '\n':
#print 'buffer ends with newline'
yield segment
else:
lines[-1] += segment
#print 'enlarged last line to >{}<, len {}'.format(lines[-1], len(lines))
segment = lines[0]
for index in range(len(lines) - 1, 0, -1):
if len(lines[index]):
yield lines[index]
# Don't yield None if the file was empty
if segment is not None:
yield segment
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-14 15:18:16
Prosta funkcja do tworzenia drugiego pliku odwróconego (tylko linux):
import os
def tac(file1, file2):
print(os.system('tac %s > %s' % (file1,file2)))
Jak używać
tac('ordered.csv', 'reversed.csv')
f = open('reversed.csv')
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-07 05:24:25
Jeśli martwisz się o rozmiar pliku / użycie pamięci, mapowanie pamięci pliku i skanowanie wstecz w poszukiwaniu nowych linii jest rozwiązaniem:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-08 10:29:46
def reverse_lines(filename):
y=open(filename).readlines()
return y[::-1]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-13 05:32:01
Zawsze używaj with
podczas pracy z plikami, ponieważ obsługuje wszystko za Ciebie:
with open('filename', 'r') as f:
for line in reversed(f.readlines()):
print line
Lub w Pythonie 3:
with open('filename', 'r') as f:
for line in reversed(list(f.readlines())):
print(line)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-02 15:19:59
Najpierw trzeba otworzyć plik w formacie odczytu, zapisać go do zmiennej, a następnie otworzyć drugi plik w formacie zapisu, w którym można zapisać lub dołączyć zmienną za pomocą plasterka [:: -1] , całkowicie odwracając plik. Możesz również użyć metody readlines (), aby przekształcić ją w listę linii, którą możesz manipulować
def copy_and_reverse(filename, newfile):
with open(filename) as file:
text = file.read()
with open(newfile, "w") as file2:
file2.write(text[::-1])
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-07 12:47:47
Większość odpowiedzi musi przeczytać cały plik przed zrobieniem czegokolwiek. Próbka ta odczytuje coraz większe próbki od końca .
Widziałem tylko odpowiedź Murata Yükselena pisząc tę odpowiedź. To prawie to samo, co, jak sądzę, jest dobrą rzeczą. Poniższy przykład dotyczy również \r i zwiększa jego rozmiar bufora na każdym kroku. Mam też kilka testów jednostkowych , aby potwierdzić ten kod.
def readlines_reversed(f):
""" Iterate over the lines in a file in reverse. The file must be
open in 'rb' mode. Yields the lines unencoded (as bytes), including the
newline character. Produces the same result as readlines, but reversed.
If this is used to reverse the line in a file twice, the result is
exactly the same.
"""
head = b""
f.seek(0, 2)
t = f.tell()
buffersize, maxbuffersize = 64, 4096
while True:
if t <= 0:
break
# Read next block
buffersize = min(buffersize * 2, maxbuffersize)
tprev = t
t = max(0, t - buffersize)
f.seek(t)
lines = f.read(tprev - t).splitlines(True)
# Align to line breaks
if not lines[-1].endswith((b"\n", b"\r")):
lines[-1] += head # current tail is previous head
elif head == b"\n" and lines[-1].endswith(b"\r"):
lines[-1] += head # Keep \r\n together
elif head:
lines.append(head)
head = lines.pop(0) # can be '\n' (ok)
# Iterate over current block in reverse
for line in reversed(lines):
yield line
if head:
yield head
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-10 21:35:22
Musiałem to zrobić jakiś czas temu i użyłem poniższego kodu. Do muszli. Obawiam się, że nie mam już kompletnego scenariusza. Jeśli korzystasz z systemu operacyjnego unixish, możesz użyć "tac", jednak na przykład Mac OSX polecenie tac nie działa, użyj tail-r. poniższy fragment kodu testuje, na której platformie się znajdujesz, i odpowiednio dostosowuje polecenie
# We need a command to reverse the line order of the file. On Linux this
# is 'tac', on OSX it is 'tail -r'
# 'tac' is not supported on osx, 'tail -r' is not supported on linux.
if sys.platform == "darwin":
command += "|tail -r"
elif sys.platform == "linux2":
command += "|tac"
else:
raise EnvironmentError('Platform %s not supported' % sys.platform)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-07 23:20:03