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
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.
| Mode | Meaning |
|---|---|
"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
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:
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:
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()andwrite_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,.stemand.suffixgive 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()andfor line in fread text;write()needs explicit"\n".pathlib.Pathbuilds paths that work everywhere.csv.DictReaderreads rows as dictionaries;json.dumpandjson.loadsave and load Python data.
Python File Handling Examples
Each example shows the code, the output it produces and what each part does.
Reading a file line by line
shopping.txt contains three lines: milk, bread and eggs.
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")1. milk
2. bread
3. eggs
4 items nowLine-by-line explanation
- Line 2enumerate() numbers the lines as we loop, starting at 1.
- Line 3strip() removes the newline at the end of each line.
- Lines 5 to 6Append mode adds a line without touching the existing ones.
- Lines 8 to 9readlines() returns a list, so len() counts the lines.
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.
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}")pen 12.00
notebook 14.00
lamp 24.50
TOTAL 50.50Line-by-line explanation
- Line 4newline="" is recommended by the csv module so that line endings are handled correctly.
- Line 5DictReader uses the header row as the keys of each row's dictionary.
- Line 6Every value in a CSV file is text, so convert numbers before doing maths.
- Line 8:<9 and :>6.2f line the columns up.
Saving and loading JSON
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"))jazz True
{
"theme": "dark",
"volume": 7,
"favourites": [
"jazz",
"lofi"
]
}Line-by-line explanation
- Lines 7 to 8dump() turns the dictionary into JSON text and writes it.
- Lines 10 to 11load() reads the text and rebuilds the dictionary.
- Line 13The loaded data is equal to the original.
- Line 14read_text() shows the file contents; indent=2 made it readable.
Common Python File Handling Mistakes
Forgetting to close a file
file = open("log.txt", "a")
file.write("Started\n")
# the file may not be saved if the program crashes herewith open("log.txt", "a", encoding="utf-8") as file:
file.write("Started\n")Using "w" when you meant "a"
with open("diary.txt", "w", encoding="utf-8") as f:
f.write("Today was great\n") # every earlier entry is gonewith open("diary.txt", "a", encoding="utf-8") as f:
f.write("Today was great\n")Doing maths with CSV text
total = row["qty"] * row["price"] # TypeError: can't multiply str by strtotal = 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.
Complete the code so the file is closed automatically.
open("notes.txt", encoding="utf-8") f:
print(f.read())
Which mode adds text to the end of a file without deleting what's there?
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())
Which function saves a Python dictionary to a file as JSON?
Why is csv.DictReader handy?
Python File Handling Quiz
5 questions to check what you learned.
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
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
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
What type are the values in a row from
csv.DictReader?- Strings
- Numbers where possible
- Lists
- Booleans
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