<p>Whlie@martineau的解决方案在没有将整个文件加载到内存的情况下完成了任务,但是它会浪费时间读取整个文件两次。你知道吗</p>
<p>一种可以说更有效的一次性方法是从文件末尾以相当大的块读入缓冲区,从缓冲区末尾查找下一个换行符(减去最后一个字符的尾随换行符),如果找不到,则向后查找并继续以块读入,并将块预先放入缓冲区,直到找到为止找到换行符。使用较大的块大小进行更有效的读取,只要它在内存限制内:</p>
<pre><code>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
</code></pre>
<p>以便:</p>
<pre><code>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='')
</code></pre>
<p>输出:</p>
<pre><code>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
</code></pre>