File Handling

Intermediate · 18 min read · ▶ live playground · ✦ checkpoint

A program gets much more useful the moment it can leave notes for itself. A score list, a saved draft, a tiny receipt log — file handling means reading from and writing to named pieces of data on disk, so your program can work with text outside its own source code.

In this browser, files live in a temporary page filesystem. Write and read them inside the same program, and remember that a page reload clears that little workspace.

Opening a file

A file is a named chunk of data, and a path is the address Python uses to find it. Opening a file is like checking out a notebook from a desk: you tell Python which notebook you want and whether you plan to read, erase, or add pages.

The built-in open() function returns a file object, which is the value your code uses to talk to the open file.

note = open("mood.txt", "w")
note.write("Mina feels focused.\n")
note.write("Ravi brings apples.\n")
note.close()
 
note = open("mood.txt", "r")
text = note.read()
note.close()
 
print(text, end="")

Mina feels focused.
Ravi brings apples.

The "w" is the mode, the short string that tells Python what kind of access you want. "w" means write. It creates the file if it does not exist, and it replaces the old contents if it does.

close() matters because an open file can still have unwritten data waiting in a buffer. A buffer is a small waiting room where Python may hold data before sending it to the file. Closing says, "finish the work and put the notebook back."

File modes

Modes are tiny, but they change everything:

  • "r" means read an existing file.
  • "w" means write a fresh file, replacing old contents.
  • "a" means append, adding new text to the end.
  • "x" means create a new file, but fail if it already exists.
  • "b" means binary mode, file access for non-text data like images or PDFs; you only need the idea here, and you will use it for automation work in lesson 24.1.
  • "+" means read/write mode, access that can both read and write through the same file object; beginners rarely need it at first.

If you open a file for reading and it is not there, Python raises FileNotFoundError, which is Python's way of saying "that path does not point to a file I can open."

open("ghost-score-never-written.txt", "r")

For now, do not try to recover from that error yet. Handling errors cleanly is the job of lesson 9.3.

Reading patterns

Reading is not one operation. You choose the shape that matches the job: the whole file, one line, all lines as a list, or one line at a time in a loop.

scores = open("scores.txt", "w")
scores.write("Mina,42\n")
scores.write("Ravi,35\n")
scores.write("Noor,39\n")
scores.close()
 
scores = open("scores.txt", "r")
print("readline:", scores.readline().strip())
print("readline:", scores.readline().strip())
scores.close()
 
scores = open("scores.txt", "r")
lines = scores.readlines()
scores.close()
 
print("list:", lines)
 
scores = open("scores.txt", "r")
for line in scores:
    print("loop:", line.strip())
scores.close()

readline: Mina,42
readline: Ravi,35
list: ['Mina,42\n', 'Ravi,35\n', 'Noor,39\n']
loop: Mina,42
loop: Ravi,35
loop: Noor,39

read() gives one big string. readline() gives the next line each time you call it. readlines() gives a list of strings. Looping over the file object gives one line per pass, which is often the cleanest pattern.

Notice the \n characters in the list output. Files store line breaks as characters too. .strip() removes the line break when you want clean display text.

Writing and appending

Writing starts from a blank page when you use "w". Appending starts at the end when you use "a".

log = open("snack-log.txt", "w")
log.write("Monday: apples\n")
log.write("Tuesday: tea\n")
log.close()
 
log = open("snack-log.txt", "a")
log.write("Wednesday: mango\n")
log.close()
 
log = open("snack-log.txt", "r")
print(log.read(), end="")
log.close()

Monday: apples
Tuesday: tea
Wednesday: mango

write() returns the number of characters written, but most programs ignore that value unless they are measuring file work. The more common beginner mistake is forgetting \n, then all the written pieces run together on one line.

Try it — make a tiny receipt file

Run this, then change the items. Keep the write and the read in the same program so the browser has the file when it needs it.

python — playgroundlive
⌘/Ctrl + Enter to run

The with statement

Manual close() works, but it is easy to forget. The with statement gives a safer pattern:

with open("team.txt", "w") as team_file:
    team_file.write("Mina\n")
    team_file.write("Ravi\n")
    team_file.write("Noor\n")
 
with open("team.txt", "r") as team_file:
    for name in team_file:
        print("ready:", name.strip())

ready: Mina
ready: Ravi
ready: Noor

A context manager is an object that sets something up at the start of a with block and cleans it up at the end; you will build your own in lesson 12.3. For files, that cleanup means closing the file for you. Think of with as borrowing the notebook for just the indented block; when the block ends, Python returns it.

Use with open(...) as name: for most file code. It is shorter, and it makes the lifetime of the open file visible.

Paths with os.path and pathlib

A filename like "team.txt" is a relative path, which means "look near where the program is running." An absolute path starts from the top of the filesystem and points to one place directly.

You can build paths with os.path, which works with path strings:

import os
 
folder = "reports"
filename = "score-summary.txt"
path = os.path.join(folder, filename)
 
print(path)
print(os.path.basename(path))
print(os.path.dirname(path))

reports/score-summary.txt
score-summary.txt
reports

You can also use pathlib.Path, which treats paths as objects with helpful methods:

from pathlib import Path
 
path = Path("reports") / "score-summary.txt"
 
print(path.as_posix())
print(path.name)
print(path.parent.as_posix())

reports/score-summary.txt
score-summary.txt
reports

Path("reports") / "score-summary.txt" may look strange at first. Here / is not division; pathlib uses it as a readable way to join path pieces. For new code, pathlib is often the friendlier choice, while os.path is still common in older code and examples.

Checkpoint

Answer all three to mark this lesson complete

Raw text files are useful, but they make your program do all the organizing. Next, you will use CSV and JSON so Python can store rows, dictionaries, and lists in formats other tools understand too.

+50 XP on completion