Article
Read and write JSON, CSV and text files in Python
Open, read and save text, JSON and CSV files in Python using pathlib and the with statement, plus the encoding and newline settings that stop silent corruption.
On this page0%
- Paths first: use pathlib
- Text files
- Always pass encoding="utf-8"
- JSON files
- CSV files
- Reading rows as dictionaries
- Writing rows
- Why newline=""?
- When to reach for pandas instead
- A tiny practical example
- Common errors
- FAQ
- What is the best way to read a file in Python?
- How do I save a Python dictionary to a JSON file?
- Why does my CSV have blank lines between rows on Windows?
- Should I use pathlib or os.path?
- Next reading on Sythra Articles
Almost every useful script reads something from disk or saves something back. Python makes the three most common formats — plain text, JSON and CSV — easy, but a few defaults can quietly bite you. This guide covers the safe way to do each.
Paths first: use pathlib
Stop gluing paths together with strings. pathlibA built-in module that represents file paths as objects instead of plain strings works the same on Windows, macOS and Linux:
from pathlib import Path
folder = Path("data")
notes = folder / "notes.txt" # the / joins path pieces
print(notes) # data\notes.txt on Windows, data/notes.txt elsewhere
print(notes.exists()) # True or False
print(notes.suffix) # .txt
print(notes.name) # notes.txt
Create the folder before writing into it:
folder.mkdir(exist_ok=True)
Text files
The safe pattern is the with statement. It closes the file for you, even if your code crashes halfway:
from pathlib import Path
path = Path("data/notes.txt")
# Write (overwrites anything already there)
path.write_text("first line\nsecond line\n", encoding="utf-8")
# Read everything
text = path.read_text(encoding="utf-8")
print(text)
For big files, read line by line instead of loading everything:
with open(path, encoding="utf-8") as f:
for line in f:
print(line.rstrip("\n"))
To add to the end without erasing, use mode "a":
with open(path, "a", encoding="utf-8") as f:
f.write("third line\n")
Always pass encoding="utf-8"
On Windows the default encoding can be a legacy code page. A file with accents, emoji or non-English names then reads as garbage or raises UnicodeDecodeError. Saying encoding="utf-8" every time removes the whole class of bug.
JSON files
JSONA text format for structured data using objects, lists, strings and numbers; the common language of web APIs maps neatly onto Python dictionaries and lists.
import json
from pathlib import Path
settings = {
"name": "Sythra",
"tags": ["python", "ml"],
"retries": 3,
"debug": False,
}
path = Path("settings.json")
# Save
with open(path, "w", encoding="utf-8") as f:
json.dump(settings, f, indent=2, ensure_ascii=False)
# Load
with open(path, encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["tags"]) # ['python', 'ml']
Two options worth knowing:
indent=2makes the file readable for humans and tidy in version control.ensure_ascii=Falsekeeps characters likeéreadable instead of writingé.
JSON only supports basic types. A datetime, set or custom object raises TypeError: Object of type ... is not JSON serializable. Convert it first — for example date.isoformat() or list(my_set).
If a file is empty or hand-edited and broken, json.load raises json.JSONDecodeError. Catch it when the file comes from a user:
try:
with open("settings.json", encoding="utf-8") as f:
data = json.load(f)
except FileNotFoundError:
data = {}
except json.JSONDecodeError as error:
print(f"settings.json is not valid JSON: {error}")
data = {}
CSV files
Python's csv module handles quoting and commas inside values, which naive line.split(",") gets wrong.
Reading rows as dictionaries
import csv
with open("students.csv", newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
print(row["name"], row["score"])
DictReader uses the header row for keys, so you write row["score"] instead of remembering that score is column 2.
Note that every value arrives as a string. Convert when you need numbers:
total = 0
with open("students.csv", newline="", encoding="utf-8") as f:
for row in csv.DictReader(f):
total += float(row["score"])
print(total)
If you meet could not convert string to float, see our string-to-float fix.
Writing rows
import csv
rows = [
{"name": "Ada", "score": 92},
{"name": "Grace", "score": 88},
]
with open("out.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["name", "score"])
writer.writeheader()
writer.writerows(rows)
Why newline=""?
The csv module manages line endings itself. Without newline="", files written on Windows can end up with a blank line between every row. Always include it for CSV.
When to reach for pandas instead
For small, simple files the standard library is enough. Once you want filtering, grouping, missing-value handling or hundreds of thousands of rows, pandas.read_csv("file.csv") is shorter and faster. See cleaning a messy CSV with pandas.
A tiny practical example
Read a JSON list of tasks, mark one as done, save it back:
import json
from pathlib import Path
path = Path("tasks.json")
tasks = json.loads(path.read_text(encoding="utf-8")) if path.exists() else []
tasks.append({"title": "Write article", "done": False})
tasks[0]["done"] = True
path.write_text(json.dumps(tasks, indent=2), encoding="utf-8")
print(f"{len(tasks)} task(s) saved")
Check-then-write is the shape of most small tools: load, change, save.
Common errors
| Error | Usual cause | Fix |
|---|---|---|
FileNotFoundError | Wrong path or wrong working folder | Print Path.cwd() and use an absolute path |
UnicodeDecodeError | File is not in the encoding Python guessed | Pass encoding="utf-8" (or the file's real encoding) |
PermissionError | File is open in Excel or another program | Close it, then retry |
JSONDecodeError | Empty file, trailing comma, single quotes | Validate the file; JSON requires double quotes |
FAQ
What is the best way to read a file in Python?
Use Path.read_text(encoding="utf-8") for small files or with open(path, encoding="utf-8") as f: and loop over f for large ones. The with block closes the file automatically.
How do I save a Python dictionary to a JSON file?
Open the file in write mode and call json.dump(data, f, indent=2). Load it back later with json.load(f).
Why does my CSV have blank lines between rows on Windows?
You forgot newline="" when opening the file for writing. Pass newline="" to open() whenever you use the csv module.
Should I use pathlib or os.path?
Prefer pathlib for new code. It reads more clearly and handles path separators for you on every operating system.