File Handling
Almost every real program eventually needs to read data from disk or save results to a file — configuration files, logs, CSV exports, saved user data, and more. Python's built-in open() function is the entry point for all of this. This page covers how to open files safely, the different modes you can open them in, and the core methods for reading and writing.
Opening a File with `open()`
open() takes a file path and a mode string that tells Python what you intend to do with the file — read it, write to it, append to it, and so on. It returns a file object that you use to interact with the file's contents.
f = open("notes.txt", "r")
contents = f.read()
print(contents)
f.close()The example above works, but it has a problem: if an error happens between open() and f.close(), the file may never get closed. The next section explains why that matters and shows the safer, idiomatic way to do this.
File Modes
The second argument to open() is the mode. It controls whether the file is opened for reading or writing, whether existing content is kept or erased, and whether the data is treated as text or raw bytes.
Mode | Meaning |
|---|---|
| Read (default). Fails with |
| Write. Creates the file if missing, overwrites it completely if it exists. |
| Append. Creates the file if missing, adds new content to the end if it exists. |
| Exclusive create. Fails with |
| Read and write. File must already exist; does not truncate it. |
| Read and write. Creates or overwrites the file first. |
| Read in binary mode (returns |
| Write in binary mode (overwrites, writes |
| Append in binary mode. |
Always Use `with open(...) as f:`
Python's with statement wraps file access in a context manager that automatically calls f.close() for you — even if an exception is raised inside the block. This is the idiomatic way to work with files, and you should use it by default.
with open("notes.txt", "r") as f:
contents = f.read()
print(contents)
# f.close() is called automatically here, even if read() had raised an errorCompare the risky manual version to the safe with version:
# Risky: if write_report() raises, close() never runs
f = open("report.txt", "w")
write_report(f)
f.close()
# Safe: close() always runs, even on error
with open("report.txt", "w") as f:
write_report(f)Reading a File
Once a file is open for reading, there are three common ways to pull data out of it.
.read()— reads the entire file as one string..readline()— reads a single line at a time, including the trailing newline..readlines()— reads the whole file and returns a list of lines.
with open("poem.txt", "r", encoding="utf-8") as f:
whole_thing = f.read()
print(repr(whole_thing))
with open("poem.txt", "r", encoding="utf-8") as f:
first_line = f.readline()
second_line = f.readline()
print(repr(first_line))
print(repr(second_line))
with open("poem.txt", "r", encoding="utf-8") as f:
all_lines = f.readlines()
print(all_lines)'Roses are red\nViolets are blue\n' 'Roses are red\n' 'Violets are blue\n' ['Roses are red\n', 'Violets are blue\n']
Writing to a File
.write() writes a single string to the file. Unlike print(), it does not add a newline automatically — you have to include \\n yourself. .writelines() writes an iterable of strings in sequence, also without adding newlines between them.
with open("todo.txt", "w", encoding="utf-8") as f:
f.write("Buy milk\n")
f.write("Walk the dog\n")
with open("todo.txt", "a", encoding="utf-8") as f:
f.writelines(["Water the plants\n", "Read a book\n"])
with open("todo.txt", "r", encoding="utf-8") as f:
print(f.read())Buy milk Walk the dog Water the plants Read a book
Checking Whether a File Exists
Opening a missing file in read mode raises FileNotFoundError. You can guard against this either by checking beforehand with os.path.exists(), or — usually the more Pythonic approach — by simply trying to open the file and catching the exception.
import os
path = "settings.json"
if os.path.exists(path):
with open(path, "r", encoding="utf-8") as f:
print(f.read())
else:
print(f"{path} does not exist yet")
# Alternative: try/except is often preferred (see also the pathlib page for .exists())
try:
with open(path, "r", encoding="utf-8") as f:
data = f.read()
except FileNotFoundError:
print(f"{path} does not exist yet")
data = ""settings.json does not exist yet settings.json does not exist yet
with open(...) as f:closes the file automatically and should be your default.'r','w','a', and'x'control read/overwrite/append/create-only behavior..read(),.readline(), and.readlines()give you three levels of granularity for reading..write()and.writelines()do not add newlines automatically — you must include\n.