HOWTO · Python
How to Read Last Line of File Using Python
Learn how to read a file’s last line in Python with a loop, readlines(), deque, backward binary reading with seek(), or the optional Unix-like tail command.
On this page
To get the last line in Python, iterate through the file and keep the most recent line. This scans the file from beginning to end but stores only one line at a time. For a very large file where scanning everything is too slow, read backward in binary chunks instead.
Run this example:
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "sample.txt"
path.write_text("alpha\nbeta\ngamma\n", encoding="utf-8")
last_line = None
with path.open("r", encoding="utf-8") as file:
for line in file:
last_line = line.rstrip("\r\n")
print(last_line)
gamma
Read the Last Line of a File in Python
Python file objects do not offer a direct “last line” operation. A line-by-line read is simple and uses little extra memory, but it still has to reach the end of the file. If the file is small enough to fit comfortably in memory, readlines() is shorter; for a large file, a backward binary scan can avoid reading earlier content. The best choice depends on whether simplicity, memory use, or avoiding a full scan matters most.
Read Line by Line with a for Loop
Keep a variable for the most recently read line. Initializing it to None gives the code a defined result when there are no lines. rstrip("\r\n") removes only line-ending characters, so spaces that belong to the content are preserved.
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "sample.txt"
path.write_text("first\nsecond\n", encoding="utf-8")
last_line = None
with path.open("r", encoding="utf-8") as file:
for line in file:
last_line = line.rstrip("\r\n")
print(last_line)
The loop reads every line, so its time cost grows with the file size. Its additional memory use is limited to the current line and the saved result. A final newline does not create an extra line in Python’s text iterator; a blank final line represented by two newline characters is returned as an empty string.
Use readlines() for Small Files
readlines() returns all lines in a list, so the last item is easy to select. Check the list before indexing because a file with no content produces an empty list. Text mode keeps each line ending in the returned string; remove only \r and \n if the caller wants the content without its terminator.
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "sample.txt"
path.write_text("first\nsecond\n", encoding="utf-8")
with path.open("r", encoding="utf-8") as file:
lines = file.readlines()
last_line = lines[-1].rstrip("\r\n") if lines else None
print(last_line)
This also scans the complete file and holds every line in memory. Use it when that list is useful elsewhere or the file is modest in size; do not use strip() if leading or trailing spaces may be meaningful.
Keep Only the Last Line with deque
A deque with maxlen=1 discards older items as each new line arrives. It offers the same sequential scan and low memory use as the loop, with less explicit state. Guard the result before calling pop() so the function also handles a file with no lines.
from collections import deque
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "sample.txt"
path.write_text("first\nsecond\n", encoding="utf-8")
with path.open("r", encoding="utf-8") as file:
lines = deque(file, maxlen=1)
last_line = lines.pop().rstrip("\r\n") if lines else None
print(last_line)
deque limits retained lines, not the amount of input read: it still reaches the end. It is useful when you want to keep only the latest item while streaming a file.
Read Backward from the End with seek()
For a large file, opening it in binary mode allows seek() to move to byte offsets safely. The function below starts at the end, removes one final line feed when present, then searches backward in fixed-size chunks for the preceding line feed. It joins only the chunks belonging to the last line, so memory use depends on that line’s length rather than the whole file. It supports LF and CRLF line endings and decodes the selected bytes using the requested encoding.
from pathlib import Path
from tempfile import TemporaryDirectory
def read_last_line(path, encoding="utf-8", chunk_size=8192):
if chunk_size <= 0:
raise ValueError("chunk_size must be positive")
with open(path, "rb") as file:
file.seek(0, 2)
end = file.tell()
if end == 0:
return None
file.seek(end - 1)
position = end - 1 if file.read(1) == b"\n" else end
chunks = []
while position > 0:
start = max(0, position - chunk_size)
file.seek(start)
chunk = file.read(position - start)
newline = chunk.rfind(b"\n")
if newline >= 0:
chunks.append(chunk[newline + 1:])
line = b"".join(reversed(chunks))
return (line[:-1] if line.endswith(b"\r") else line).decode(encoding)
chunks.append(chunk)
position = start
line = b"".join(reversed(chunks))
return (line[:-1] if line.endswith(b"\r") else line).decode(encoding)
with TemporaryDirectory() as directory:
path = Path(directory) / "sample.txt"
path.write_bytes("first\r\nlast line\r\n".encode("utf-8"))
print(read_last_line(path))
A line longer than one chunk is accumulated until its delimiter is found; a file containing one line is read back to its beginning. The selected line must be valid in the specified encoding. This implementation treats LF and CRLF as delimiters, not files that use lone CR characters as line separators. For unusual encodings or newline conventions, use a streaming text reader or adapt the delimiter handling.
Use tail on Unix-like Systems
On systems that provide it, the external tail command can return the last line without implementing a backward scan yourself. From Python, capture its bytes with subprocess.run(["tail", "-n", "1", path], capture_output=True, check=True), then decode result.stdout with the file’s encoding. This depends on tail being installed and available on PATH, and is not a native Windows solution. Use an argument list rather than building a shell command from a path. The command’s behavior and speed depend on the operating system and file.
Choose a Method and Handle Edge Cases
| Method | Reads the whole file? | Extra memory | Use when |
|---|---|---|---|
for loop |
Yes | One line | You want straightforward streaming code. |
readlines() |
Yes | All lines | The file is small or the list is needed. |
deque with maxlen=1 |
Yes | One line | You want concise streaming state. |
Backward binary chunks with seek() |
Usually no; may reach the beginning for a long final line | Last line plus a chunk | The file is large and LF or CRLF is used. |
tail |
Depends on the implementation | External process | The target system provides the command. |
For an empty file, return None or another documented sentinel rather than indexing or popping without a check. Decide whether the result should include its line terminator; remove only \r and \n when it should not. The loop and deque use little memory but still scan the complete file. readlines() is the simplest list-based option for small files. Use the backward seek() approach when avoiding earlier reads is valuable and its encoding and newline assumptions fit the file. Choose tail when an external Unix-like utility is acceptable.