Skip to content

Instantly share code, notes, and snippets.

@zzstoatzz
Last active March 2, 2024 17:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zzstoatzz/607feb85084c491d3e456af61194b07a to your computer and use it in GitHub Desktop.
Save zzstoatzz/607feb85084c491d3e456af61194b07a to your computer and use it in GitHub Desktop.
find the last n lines of a text file assumed to end with a newline character
from pathlib import Path
def reverse_readline(filepath, N):
with filepath.open('rb') as f:
f.seek(0, 2)
filesize = f.tell()
lines_found = []
buffer = bytearray()
chunk_size = 8192 # Read in chunks of 8KB
position = filesize
while position >= 0 and len(lines_found) < N:
position -= chunk_size
if position < 0:
chunk_size += position # Adjust chunk_size if it overshoots the start of the file
position = 0
f.seek(position)
chunk = f.read(chunk_size) + buffer
lines = chunk.split(b'\n')
# Process all lines found, except potentially incomplete first line in chunk
for i in range(len(lines) - 1, 0, -1):
lines_found.append(lines[i].decode(errors='ignore'))
if len(lines_found) == N:
break
buffer = lines[0] # Handle any incomplete line by prepending it to the buffer for the next chunk
if buffer:
# Ensure any remaining buffer (e.g., the first line of the file) is included
lines_found.append(buffer.decode(errors='ignore'))
return reversed(lines_found)
filepath = Path('file.txt')
last_n_lines = reverse_readline(filepath, N=5)
for line in last_n_lines:
print(line)
@zzstoatzz
Copy link
Author

In [3]: cat file.txt
foo\n
foo\n
foo\n
foo\n
foo\n
foo\n
foo\n
bar\n
baz\n

In [4]: last_n_lines = reverse_readline(filepath, N=5)

In [5]: for line in last_n_lines:
   ...:     print(line)
   ...:
foo\n
foo\n
foo\n
bar\n
baz\n

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment