File Handling
Lesson 6 of 8
6File Handling
The big pictureHow to open a file, read it three different ways, write to it, and guarantee it always closes, even if an error happens halfway through.
What the picture shows: with opens the file, the cursor moves down one line at a time while reading, and at the end of the block the file closes on its own.
Map of this part
The concepts in order, click any one to jump to it:
Two ways into the same idea
Opening a file is like borrowing a library book: you open it to read or to write, read it all or line by line, and in the end you must return it. Forget to return it and it stays checked out. A with statement is a librarian who returns it for you automatically, even if you trip halfway through.
open(path, mode, encoding="utf-8") with modes r, w, a and b. Read with read(), readline() or by iterating line by line; the cursor advances as you read and moves with seek. with open(...) as f: guarantees close() even on an exception, and always set the encoding for Arabic text.
Required Fundamentals
| Concept | Why it matters here |
|---|---|
| Exception Handling (the Exceptions lesson) | Opening a missing file or one with wrong permissions raises an exception (FileNotFoundError, PermissionError) you must handle. |
| Loops and Lists | Reading a file line by line depends directly on a for loop. |
Core Concepts
Any interaction with a file goes through three fixed steps: open the file to get a handle pointing to it, perform a read or write operation on it, then close it to free resources and actually flush any pending buffered data to disk.
1Opening Modes
"r" read-only (default), "w" write (erases old content entirely!), "a" append at the end without erasing, "r+" read and write together.
2Three Ways to Read
.read() returns everything as one string, .readline() returns only one line per call, .readlines() returns a list of all lines.
3Cursor Position
An open file remembers "where it last stopped". .tell() tells you the current byte position, .seek(0) takes you back to the start. For example: if you read the first 50 bytes with .read(50), .tell() automatically becomes 50, and any further read continues from there, not from the beginning; calling .seek(0) takes you back to the exact start, without needing to close and reopen the file.
4Encoding
Explicitly specifying encoding="utf-8" on open protects you from reading Arabic text or special characters incorrectly across different operating systems.
Diagram 17, the with statement guarantees close() is called automatically as soon as the block exits, whether it succeeded or failed.
f = open(...) without with and then forgetting f.close(), or worse: an exception occurring between open and close, leaving the file open indefinitely in that session, with any pending buffered data never actually flushed to disk.
Applied Example: a Reading Diary
Let's build a small program that logs a "reading diary", every time you finish a book you add a new entry, and at any time you can retrieve the whole diary or check it line by line:
## Add a new entry without erasing the old ones
def add_entry(path, book_title):
with open(path, "a", encoding="utf-8") as f:
f.write(f"Finished reading: {book_title}\n")
## Read the whole diary at once
def read_all(path):
with open(path, "r", encoding="utf-8") as f:
return f.read()
## Read the diary line by line (useful for very large files)
def print_entries_one_by_one(path):
with open(path, "r", encoding="utf-8") as f:
line = f.readline()
while line:
print("📖", line.strip())
line = f.readline()
add_entry("diary.txt", "One Hundred Years of Solitude")
add_entry("diary.txt", "The Unbearable Lightness of Being")
print_entries_one_by_one("diary.txt")
add_entry used "w", every new call would erase all previous entries and start from zero! "a" appends at the end without touching what came before, this distinction is a very common source of data loss for beginners.
The Practical Difference Between the Three Read Methods
| Method | Returns | Best when |
|---|---|---|
.read() | One complete string | The file is small and you need all the content at once |
.readline() | Only one line, remembering its position for next time | You need line-by-line processing without loading the whole file into memory |
.readlines() | A list of all lines | You need all lines as a ready list to iterate over more than once |
Worked example
with open("log.txt", "a", encoding="utf-8") as f: f.write("user signed in\n"). Mode "a" appends at the end, while "w" would have wiped the whole file.Myth vs. Reality
| The myth | The reality |
|---|---|
Manual f.close() is always enough | If an exception occurs before reaching the close() line, it never runs, with guarantees closing in every case thanks to a mechanism similar to finally. |
Reading a large file with .read() is always faster | Loading a huge file (gigabytes) entirely into memory at once can exhaust all system memory, reading line by line is safer for large files. |
| The default encoding works everywhere | The default encoding differs between operating systems (Windows vs. Linux); explicitly specifying encoding="utf-8" makes your code behave identically on any machine. |
Where Is This Idea Actually Used?
Config files
Reading application settings from a text file at startup.
Logs
Appending a new line to a log file without erasing the old log, using "a" mode.
Checkpoints
Periodically saving a long process's progress to disk, to resume after an interruption.
Data export
Writing analysis results or a report to a shareable text file.
Try it yourself
Which open mode adds to the end of a file without erasing it?
"a" appends. "w" wipes the file first, "r" only reads, and "x" fails if the file exists.
Quick Review Flashcards
Check Your Understanding
1. If you accidentally open a file in "w" mode just to read it, what happens?
The file's content is erased immediately upon opening in this mode, even before writing anything, irreversible data loss. This is why "r" is the safe default mode for reading only.
2. What does with guarantee beyond manual close()?
It guarantees closing runs even when an unexpected exception occurs mid-block, exactly like a finally block always runs (the Exceptions lesson).
3. Why do you need .tell() and .seek() at all if readline() already remembers its own position?
readline() only moves forward automatically. seek() gives you manual control over position, like jumping back to the start to re-read the file, or moving to a specific byte offset without reading everything before it.
Resources for this part
Sorted by kind: start with the official docs when you want the precise reference, or with an article or video when you want the explanation first.
Resources for this lesson
Grouped by type. Start with the official docs for precision, or an article or video for the explanation.
Official docs3
Done with this lesson?
Sign in to save your progress.