Variables disappear when a program ends. To keep data, such as a to-do list, a sales report or a settings file, you save it to a file. Python file handling is straightforward: one built-in function, open(), handles reading and writing text files, and the standard library adds tools for paths, CSV spreadsheets and JSON data. Every example in this lesson creates the files it reads, so you can run each one in an empty folder.
Python file handling with open() and with
open(path, mode, encoding=...) returns a file object. Always use it inside a with block. When the block ends, Python closes the file for you, even if an error happened inside the block. An unclosed file can lose data that was not yet written to disk.
| Mode | Meaning |
|---|---|
"r" | Read (the default). Error if the file does not exist. |
"w" | Write. Creates the file, or empties it if it already exists. |
"a" | Append. Adds to the end; creates the file if needed. |
"x" | Create. Error if the file already exists, so nothing is overwritten by accident. |
"rb", "wb" | Binary read or write, for images, PDFs and other non-text files. |
Always pass encoding="utf-8" for text files. Without it, Python may use your operating system’s default encoding, and characters such as ₹ or Tamil letters may break when the file moves to another computer.
with open("tasks.txt", "w", encoding="utf-8") as f:
f.write("Pay electricity bill\n")
f.write("Book train to Rameswaram\n")
with open("tasks.txt", "a", encoding="utf-8") as f:
f.write("Buy flowers for Pongal\n")
with open("tasks.txt", encoding="utf-8") as f:
content = f.read()
print(content)
with open("tasks.txt", encoding="utf-8") as f:
for number, line in enumerate(f, start=1):
print(number, line.strip())Pay electricity bill Book train to Rameswaram Buy flowers for Pongal 1 Pay electricity bill 2 Book train to Rameswaram 3 Buy flowers for Pongal
write() does not add a new line for you, so each string ends with \n. When reading, read() returns the whole file as one string, and looping over the file object gives one line at a time, each still ending in \n. That is why the loop calls strip(). It also explains the empty line in the output: the text from read() already ends with \n, and print() adds one more. Reading line by line also works for very large files, because Python does not load the whole file into memory.
Watch out: Opening an existing file with "w" wipes its contents immediately, before you write anything. If you want to add to a file, use "a"; if you must never overwrite, use "x".
Paths with pathlib
File paths look different on Windows (C:\Users\…) and on macOS or Linux (/home/…). The pathlib module hides those differences. A Path object joins parts with the / operator, tells you a file’s name, extension and whether it exists, and has short helpers for small files: write_text() and read_text() open, write or read, and close in one call.
from pathlib import Path
reports = Path("reports")
reports.mkdir(exist_ok=True)
for month in ["jan", "feb", "mar"]:
(reports / f"sales-{month}.txt").write_text(f"Sales report for {month}\n", encoding="utf-8")
for file in sorted(reports.glob("*.txt")):
print(file.name, "|", file.stem, "|", file.suffix)
feb = reports / "sales-feb.txt"
print(feb.exists())
print(feb.read_text(encoding="utf-8").strip())
print((reports / "sales-dec.txt").exists())sales-feb.txt | sales-feb | .txt sales-jan.txt | sales-jan | .txt sales-mar.txt | sales-mar | .txt True Sales report for feb False
mkdir(exist_ok=True) creates the folder but does not complain if it is already there. glob("*.txt") finds matching files; its order depends on the operating system, so the example sorts the results to get a predictable list.
CSV files
CSV (comma-separated values) is the simplest way to exchange table data with Excel or Google Sheets. Do not split lines on commas yourself: a value such as "Mylapore, Chennai" contains a comma of its own. The built-in csv module handles quoting correctly. Open CSV files with newline="", as the documentation recommends, so line endings are handled properly on every system.
import csv
rows = [
["name", "area", "amount"],
["Ramesh", "Mylapore, Chennai", 1250],
["Fathima", "Gandhipuram, Coimbatore", 980],
["Joseph", "Fort Kochi", 1500],
]
with open("collections.csv", "w", newline="", encoding="utf-8") as f:
csv.writer(f).writerows(rows)
total = 0
with open("collections.csv", newline="", encoding="utf-8") as f:
for row in csv.DictReader(f):
print(f"{row['name']:<8} {row['area']:<24} ₹{row['amount']}")
total += int(row["amount"])
print("Total collected: ₹" + str(total))Ramesh Mylapore, Chennai ₹1250 Fathima Gandhipuram, Coimbatore ₹980 Joseph Fort Kochi ₹1500 Total collected: ₹3730
csv.DictReader uses the first row as headings and gives you each following row as a dictionary, so you can write row["amount"] instead of remembering column numbers. Every value comes back as a string, so convert numbers with int() or float() before doing maths.
JSON files
JSON is the format web APIs and many apps use for structured data. The json module converts Python dictionaries and lists to JSON text and back. json.dump() writes to a file and json.load() reads from one. Wrapping file access in try/except FileNotFoundError lets your program handle a missing file politely; you will learn more about this in Python Modules and Errors.
import json
from pathlib import Path
settings = {"theme": "dark", "language": "ta", "font_size": 16, "cities": ["Madurai", "Salem"]}
with open("settings.json", "w", encoding="utf-8") as f:
json.dump(settings, f, indent=2)
with open("settings.json", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["theme"], loaded["cities"][1])
print(Path("settings.json").read_text(encoding="utf-8").splitlines()[1])
try:
with open("missing.json", encoding="utf-8") as f:
data = json.load(f)
except FileNotFoundError:
print("No saved file yet, using defaults.")dark Salem "theme": "dark", No saved file yet, using defaults.
The middle line of output is the second line of the saved file. indent=2 spreads the JSON over several indented lines, so people can read and edit it; leave it out and everything is written on one compact line. json.load() gives back ordinary Python dictionaries and lists, so loaded["cities"][1] works exactly as in Python Dictionaries and Sets.
Tip: In Python file handling, relative paths such as "tasks.txt" are relative to the current working directory, which is the folder your terminal is in when you run the program, not necessarily the folder of the .py file. If a file seems to be missing, print Path.cwd() to see where Python is looking.
