Reading & Writing Files
Everything stored in variables disappears when your program ends. To keep data, such as a list of students, a shop's daily sales or a game's high score, you save it in a file. Python makes reading and writing text files short and safe.
In this lesson you will open files with the with statement, pick the right mode, handle missing files, and work with paths and folders using the modern pathlib module. The examples run in the browser, where files live in a temporary folder that is cleared later.
Writing a file with open() and with
The built-in open() function opens a file and returns a file object that you read from or write to. Always open files inside a with block. When the block ends, Python closes the file for you, even if an error happens, so your data is saved properly.
with open("students.txt", "w", encoding="utf-8") as file:
file.write("Aarav,Rohtak,82\n")
file.write("Priya,Jaipur,91\n")
file.write("Farhan,Lucknow,76\n")
print("File saved")File saved
open() takes three important arguments here:
- The file name (or path):
"students.txt". - The mode:
"w"means write. It creates the file, or empties it if it already exists. - The encoding:
"utf-8", the standard way to store text, which handles every language and symbol including Hindi and ₹.
write() does not add a new line by itself, so each string ends with \n.
File modes
| Mode | Meaning | If the file exists | If it does not exist |
|---|---|---|---|
"r" | Read (the default) | Reads it | FileNotFoundError |
"w" | Write | Empties it first | Creates it |
"a" | Append | Adds to the end | Creates it |
"x" | Create only | FileExistsError | Creates it |
Add b for binary files such as images ("rb", "wb"). Binary files hold bytes, not text, so you do not pass an encoding for them.
Reading a file
You can read the whole file as one string with read(), or, more commonly, loop over the file object to get one line at a time. Looping is memory-friendly, because Python never holds the whole file at once.
with open("students.txt", "w", encoding="utf-8") as file:
file.write("Aarav,Rohtak,82\nPriya,Jaipur,91\nFarhan,Lucknow,76\n")
with open("students.txt", encoding="utf-8") as file:
print(repr(file.read()))
total = 0
with open("students.txt", encoding="utf-8") as file:
for line in file:
name, city, marks = line.strip().split(",")
total += int(marks)
print(f"{name:<8} {city:<8} {marks}")
print("Total marks:", total)'Aarav,Rohtak,82\nPriya,Jaipur,91\nFarhan,Lucknow,76\n' Aarav Rohtak 82 Priya Jaipur 91 Farhan Lucknow 76 Total marks: 249
Each line keeps its \n at the end, which is why the loop calls strip() before splitting. Everything read from a text file is a string, so int() converts the marks before adding them. Mode "r" is the default, so the read calls leave it out. For files with columns like this one, the csv module is even better; see JSON & CSV.
Appending and handling missing files
Mode "a" adds new text to the end without touching what is already there. It is perfect for logs. Reading a file that does not exist raises FileNotFoundError, which you can catch (see Errors & Exceptions).
for entry in ["09:00 Shop opened", "13:30 Lunch break", "21:00 Shop closed"]:
with open("shop_log.txt", "a", encoding="utf-8") as log:
print(entry, file=log)
with open("shop_log.txt", encoding="utf-8") as log:
print(log.read(), end="")
try:
with open("sales_2019.txt", encoding="utf-8") as old:
print(old.read())
except FileNotFoundError:
print("No file for 2019 yet")09:00 Shop opened 13:30 Lunch break 21:00 Shop closed No file for 2019 yet
Notice print(entry, file=log): print() can write to a file, and it adds the newline for you.
Working with paths using pathlib
File names often come with folders, and folders are written differently on Windows (C:\Users\Isha) and Linux or macOS (/home/isha). The pathlib module handles these differences. A Path object represents a location, and the / operator joins parts together correctly on every system.
from pathlib import Path
reports = Path("reports") / "2026"
reports.mkdir(parents=True, exist_ok=True)
daily = reports / "sales-oct.txt"
daily.write_text("Chai: ₹1,840\nSamosa: ₹960\n", encoding="utf-8")
print(daily)
print(daily.name, daily.stem, daily.suffix)
print(daily.exists(), daily.parent)
print(daily.read_text(encoding="utf-8").splitlines())
for path in sorted(reports.glob("*.txt")):
print("Found:", path.name)reports/2026/sales-oct.txt sales-oct.txt sales-oct .txt True reports/2026 ['Chai: ₹1,840', 'Samosa: ₹960'] Found: sales-oct.txt
On Windows the paths print with backslashes, such as reports\2026\sales-oct.txt. Useful tools from this example:
mkdir(parents=True, exist_ok=True)creates the folder and any missing parent folders, and does not complain if they exist.write_text()andread_text()open, write or read, and close the file in one call..name,.stem,.suffixand.parentsplit a path into its parts.glob("*.txt")finds matching files in a folder.
Common mistakes
- Opening with
"w"by accident. Write mode erases the file immediately. Use"a"to add, and"x"when you must not overwrite. - Forgetting
with. Without it, you must callfile.close()yourself; if you forget or an error happens first, data may not be saved. - Leaving out the encoding. On Python 3.14 and older, Windows may use a different default. Always write
encoding="utf-8"for text files. - Wrong working folder. A relative name such as
"data.txt"is looked up in the folder your terminal is in, not the folder of your script. Build paths withPath(__file__).parent / "data.txt"when the file sits next to the script. - Backslashes in Windows paths. In
"C:\new\test.txt",\nand\tbecome a newline and a tab. Use forward slashes, a raw stringr"C:\new\test.txt", orPath.
Key points
- Open files with
with open(name, mode, encoding="utf-8") as f:so they are always closed. - Modes:
"r"read,"w"write (erases),"a"append,"x"create only; addbfor binary. - Loop over a file object to read it line by line, and
strip()each line. - Data read from a text file is always a string; convert numbers yourself.
pathlib.Pathjoins paths with/, creates folders and reads or writes whole files withread_text()andwrite_text().- Python 3.15 makes UTF-8 the default, but an explicit encoding is still good practice.
Exercise
Write a program for a tuition centre in Kochi. Save these attendance lines to attendance.txt using pathlib: Meera,P, Rohan,A, Isha,P, Kabir,P, Ananya,A (P means present, A absent). Then read the file back line by line and print the names of absent students and the attendance percentage.
Show solution
from pathlib import Path
path = Path("attendance.txt")
path.write_text("Meera,P\nRohan,A\nIsha,P\nKabir,P\nAnanya,A\n", encoding="utf-8")
present = 0
total = 0
with path.open(encoding="utf-8") as file:
for line in file:
name, status = line.strip().split(",")
total += 1
if status == "P":
present += 1
else:
print("Absent:", name)
print(f"Attendance: {present / total:.0%}")Absent: Rohan Absent: Ananya Attendance: 60%
Path.open() works exactly like open() but starts from a Path object. The :.0% format turns 0.6 into 60%.
Quick Quiz
1. What happens when you open an existing file with mode "w"?
Write mode truncates the file; use "a" to append or "x" to refuse overwriting.
2. Why should you open files with a with block?
The with statement guarantees the file is closed when the block ends.
3. What type is every line you read from a text file?
Text files always give strings; convert numbers with int() or float().
4. What does Path("data") / "2026" / "sales.txt" create?
The / operator joins path parts; it does not touch the disk until you read, write or mkdir().
Learn Python with a mentor
Free lessons get you started. Our Python Programming training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
