Tech With Galvan
Courses/Python Mastery/Errors & Files

Reading and Writing Files

20 min • Beginner • Module 8

Open, read, write, and close files the safe way (with).

Reading and Writing Files

Variables die with the program. Files are how data survives — and Python’s with open(...) pattern makes reading and writing them one of the cleanest parts of the language.

Writing a file

with open("notes.txt", "w") as f:
    f.write("Line one\n")
    f.write("Line two\n")

print("saved!")

Decode the line:

  • open("notes.txt", "w") — open the file in mode "w" (write)
  • as f — the open file is called f inside the block
  • f.write("...") — write text (no automatic newline — hence the \ns)
  • with — the magic: when the block ends, the file is closed automatically, even if an error happened

Always use with. Manual open()/close() works but forgetfulness causes real data loss; with makes closing impossible to forget.

The modes (there are only three you need)

Mode Name Behavior
"w" write Erases the file, then writes fresh
"a" append Keeps existing content, adds at the end
"r" read Read only (the default)

The "w" erasure surprises people:

with open("notes.txt", "w") as f:
    f.write("just this")

# notes.txt now contains ONLY "just this" — previous content gone!

Adding to a log or history? "a". Creating a fresh report? "w".

Reading a file — three ways

with open("notes.txt", "r") as f:
    # Way 1: everything as one string
    content = f.read()
    print(content)

with open("notes.txt") as f:          # "r" is the default
    # Way 2: list of lines (newlines included)
    lines = f.readlines()
    print(lines)                       # ['Line one\n', 'Line two\n']

# Way 3: line by line — the memory-friendly way
with open("notes.txt") as f:
    for line in f:
        print(line.strip())            # strip removes the trailing \n

Way 3 is the professional default — it processes one line at a time, so even a million-line file never overloads memory. The .strip() in the loop matters: each line arrives with its invisible \n attached.

The classic combo: write then read back

# Save
with open("highscore.txt", "w") as f:
    f.write("1250")

# Later... load
with open("highscore.txt") as f:
    score = int(f.read().strip())

print(f"High score: {score}")      # High score: 1250

Notice int() — files give back strings, always. Numbers round-trip through str() and int().

FileNotFoundError — your first handled file error

try:
    with open("ghost.txt") as f:
        print(f.read())
except FileNotFoundError:
    print("That file doesn't exist!")

Reading a missing file raises FileNotFoundError — wrap it when the file might legitimately be absent (first run of an app, optional config).

Common Errors & Fixes

  • FileNotFoundError — wrong filename or wrong folder. Files open relative to where you ran the script, not where the script lives. Use full paths or run from the right directory.
  • File is empty after writing — you forgot f.write() entirely, or wrote after the with block closed.
  • io.UnsupportedOperation: not readable — opened with "w" (write-only) and tried to read. Reopen with "r" or "w+".
  • Weird \n at the end of every line — that’s the line’s real newline; .strip() it.

✅ Checkpoint

  1. Which mode erases the file first? (“w”)
  2. Why with instead of open/close? (Auto-closes even on errors — can’t forget)
  3. What does each line from a for-loop read arrive with? (A trailing \n — strip it)
  4. What type is everything read from a file? (String — convert numbers yourself)

Next: JSON and CSV — the two file formats that power real applications.