def _reverse_read_lines(fp, buf_size=8192): # pylint: disable=invalid-name
"""
Async generator that returns the lines of a file in reverse order.
ref: https://stackoverflow.com/a/23646049/8776239
and: https://stackoverflow.com/questions/2301789/read-a-file-in-reverse-order-using-python
"""
segment = None # holds possible incomplete segment at the beginning of the buffer
offset = 0
await fp.seek(0, io.SEEK_END)
file_size = remaining_size = await fp.tell()
while remaining_size > 0:
offset = min(file_size, offset + buf_size)
await fp.seek(file_size - offset)
buffer = await 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):
l = lines[index]
if l:
yield l
# Don't yield None if the file was empty
if segment is not None:
yield segment
评论列表
文章目录