Python File Handling

Read and write text files safely with open() and with, and work with CSV and JSON data.

Lesson 31 of 107Intermediate18 min read

So far, everything your programs knew disappeared the moment they finished. To keep information between runs, such as a high score, a list of tasks or a day's measurements, a program needs to save it to a file and read it back later.

Python makes this straightforward. The built-in open() function connects your program to a file, and the with statement makes sure the file is closed properly afterwards, even if something goes wrong. For structured data, Python's standard library includes the csv module for spreadsheet-style files and the json module for the format used by web APIs and configuration files.

In this lesson you'll read and write plain text, build file paths that work on every operating system, and load and save CSV and JSON data. These are some of the most practical skills in Python, because so much real work starts with "take this file and...".

Opening files with with

Python
with open("notes.txt", "r", encoding="utf-8") as file:
    content = file.read()
  • open() takes the file name and a mode: what you want to do with the file.
  • with ... as file: opens the file and closes it automatically at the end of the block. Always use it.
  • Pass encoding="utf-8" so that accented letters and other characters are read the same way on every computer.
ModeMeaning
"r"Read (the default). Error if the file doesn't exist
"w"Write. Creates the file, or empties it if it exists
"a"Append. Adds to the end of the file
"x"Create. Error if the file already exists

Reading text

There are three common ways to read a text file:

  • file.read() returns the whole file as one string.
  • file.readlines() returns a list of lines, each ending in "\n".
  • Looping with for line in file: reads one line at a time, which works even for files too big to fit in memory.

Lines read from a file keep their newline character at the end, so you'll often call line.strip() before using them. If the file might be missing, catch FileNotFoundError as you learned in the error handling lesson.

Writing and appending

Python
with open("log.txt", "a", encoding="utf-8") as file:
    file.write("Backup finished\n")

write() adds exactly the text you give it, with no automatic new line, so add "\n" yourself. Mode "w" replaces everything in the file, which is easy to do by accident; use "a" when you want to keep what's already there. print("text", file=f) is another handy way to write a line, because print adds the newline for you.

Paths, CSV and JSON

The pathlib module builds file paths that work on Windows, macOS and Linux:

Python
from pathlib import Path
data_file = Path("data") / "scores.csv"
print(data_file.exists())

CSV files store tables as text, one row per line with commas between values. csv.DictReader reads each row as a dictionary keyed by the column names, and csv.writer writes rows back out.

JSON stores nested data such as lists and dictionaries as text. json.dump(data, file) saves a Python object and json.load(file) reads it back, ready to use straight away. Add indent=2 when saving to make the file easy for humans to read.

pathlib shortcuts and finding files

Path objects can read and write small files in one line, and can search folders, which saves a lot of boilerplate:

Python
from pathlib import Path

notes = Path("notes.txt")
notes.write_text("first line\n", encoding="utf-8")
print(notes.read_text(encoding="utf-8"))

for csv_file in Path("reports").glob("*.csv"):
    print(csv_file.name, csv_file.stat().st_size, "bytes")
  • read_text() and write_text() open, read or write, and close the file for you.
  • glob("*.csv") finds matching files in a folder; rglob("*.csv") searches sub-folders too.
  • .name, .stem and .suffix give the file name, the name without its extension, and the extension.

Text mode is for text. Images, PDFs and other binary files must be opened in binary mode, "rb" or "wb", which reads and writes bytes with no encoding step.

Python File Handling Syntax

File patterns

with open("file.txt", encoding="utf-8") as f:
    for line in f:
        print(line.strip())

with open("file.txt", "w", encoding="utf-8") as f:
    f.write("text\n")

import json
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, indent=2)

Python File Handling Summary

  • with open(name, mode, encoding="utf-8") as f: opens a file and closes it automatically.
  • Modes: "r" read, "w" write (overwrites), "a" append, "x" create.
  • read(), readlines() and for line in f read text; write() needs explicit "\n".
  • pathlib.Path builds paths that work everywhere.
  • csv.DictReader reads rows as dictionaries; json.dump and json.load save and load Python data.

Python File Handling Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Reading a file line by line

shopping.txt contains three lines: milk, bread and eggs.

Python
with open("shopping.txt", encoding="utf-8") as file:
    for number, line in enumerate(file, start=1):
        print(f"{number}. {line.strip()}")

with open("shopping.txt", "a", encoding="utf-8") as file:
    file.write("apples\n")

with open("shopping.txt", encoding="utf-8") as file:
    print(len(file.readlines()), "items now")
Output
1. milk
2. bread
3. eggs
4 items now
Line-by-line explanation
  1. Line 2enumerate() numbers the lines as we loop, starting at 1.
  2. Line 3strip() removes the newline at the end of each line.
  3. Lines 5 to 6Append mode adds a line without touching the existing ones.
  4. Lines 8 to 9readlines() returns a list, so len() counts the lines.
Example 2

Totals from a CSV file

sales.csv looks like this: a header row item,qty,price, then pen,10,1.20, notebook,4,3.50 and lamp,1,24.50.

Python
import csv

total = 0
with open("sales.csv", newline="", encoding="utf-8") as file:
    for row in csv.DictReader(file):
        line_total = int(row["qty"]) * float(row["price"])
        total += line_total
        print(f"{row['item']:<9} {line_total:>6.2f}")

print(f"{'TOTAL':<9} {total:>6.2f}")
Output
pen        12.00
notebook   14.00
lamp       24.50
TOTAL      50.50
Line-by-line explanation
  1. Line 4newline="" is recommended by the csv module so that line endings are handled correctly.
  2. Line 5DictReader uses the header row as the keys of each row's dictionary.
  3. Line 6Every value in a CSV file is text, so convert numbers before doing maths.
  4. Line 8:<9 and :>6.2f line the columns up.
Example 3

Saving and loading JSON

Python
import json
from pathlib import Path

settings = {"theme": "dark", "volume": 7, "favourites": ["jazz", "lofi"]}
path = Path("settings.json")

with open(path, "w", encoding="utf-8") as file:
    json.dump(settings, file, indent=2)

with open(path, encoding="utf-8") as file:
    loaded = json.load(file)

print(loaded["favourites"][0], loaded == settings)
print(path.read_text(encoding="utf-8"))
Output
jazz True
{
  "theme": "dark",
  "volume": 7,
  "favourites": [
    "jazz",
    "lofi"
  ]
}
Line-by-line explanation
  1. Lines 7 to 8dump() turns the dictionary into JSON text and writes it.
  2. Lines 10 to 11load() reads the text and rebuilds the dictionary.
  3. Line 13The loaded data is equal to the original.
  4. Line 14read_text() shows the file contents; indent=2 made it readable.

Common Python File Handling Mistakes

Forgetting to close a file

Don't
file = open("log.txt", "a")
file.write("Started\n")
# the file may not be saved if the program crashes here
Do
with open("log.txt", "a", encoding="utf-8") as file:
    file.write("Started\n")

Using "w" when you meant "a"

Don't
with open("diary.txt", "w", encoding="utf-8") as f:
    f.write("Today was great\n")   # every earlier entry is gone
Do
with open("diary.txt", "a", encoding="utf-8") as f:
    f.write("Today was great\n")

Doing maths with CSV text

Don't
total = row["qty"] * row["price"]   # TypeError: can't multiply str by str
Do
total = int(row["qty"]) * float(row["price"])

Python File Handling in Real Projects

Files in real projects

Data analysts read CSV exports from spreadsheets and databases every day. Programs keep their settings in JSON files, servers write log files line by line in append mode, and automation scripts rename, sort and summarise thousands of files at once using pathlib. Once your data is in a file, Python can do almost anything with it.

Python File Handling FAQ

How do I check if a file exists in Python?

Use Path("data.csv").exists(), or is_file() if you need to be sure it is a file and not a folder. When you are about to open the file anyway, it is often simpler to try opening it and catch FileNotFoundError, because the file could disappear between the check and the read.

Why does Python say FileNotFoundError when the file is right there?

Relative paths are resolved from the current working directory, which is the folder you ran the command from, not necessarily the folder containing your script. Print Path.cwd() to see where Python is looking, or build the path from the script's location: Path(__file__).parent / "data.csv".

How do I read a file into a list of lines without the newline characters?

file.read().splitlines() returns a list of lines with the line endings removed. For large files, loop over the file object and call line.rstrip("\n") on each line instead, so the whole file never has to be held in memory.

Why should I pass newline="" when opening a CSV file?

The csv module handles line endings itself, including line breaks inside quoted values. Without newline="", Python's own newline translation can interfere, which on Windows produces blank rows between records when writing. The Python documentation recommends newline="" for both reading and writing CSV files.

What is the difference between json.load() and json.loads()?

json.load(file) reads JSON from an open file. json.loads(text) parses JSON from a string, such as the body of a web response. The same pattern applies to json.dump(), which writes to a file, and json.dumps(), which returns a string.

Python File Handling Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the code so the file is closed automatically.

 open("notes.txt", encoding="utf-8")  f:
    print(f.read())
Multiple choiceeasy

Which mode adds text to the end of a file without deleting what's there?

Predict the outputmedium

A file contains the two lines hi and there. What does this print?

with open("f.txt", encoding="utf-8") as f:
    print(f.readlines())
Multiple choicemedium

Which function saves a Python dictionary to a file as JSON?

Multiple choicehard

Why is csv.DictReader handy?

Python File Handling Quiz

5 questions to check what you learned.

  1. What does with open(...) guarantee?

    • The file exists
    • The file is empty
    • The file is closed when the block ends
    • The file is read-only
  2. What happens if you open an existing file with mode "w"?

    • The file is emptied before writing
    • An error is raised
    • New text is added to the end
    • Nothing changes
  3. Why add encoding="utf-8" when opening text files?

    • It makes files smaller
    • It's required for CSV files only
    • It encrypts the file
    • So characters such as é or ñ are read and written consistently on every system
  4. What type are the values in a row from csv.DictReader?

    • Strings
    • Numbers where possible
    • Lists
    • Booleans
  5. What does the mode "a" do in open("log.txt", "a")?

    • Opens the file read-only
    • Deletes the file first
    • Adds new text to the end, creating the file if needed
    • Opens it as binary