Sythra

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.

vaibhavkothari· Nov 12, 2026· 5 min readBeginner
ShareXLinkedIn
Read and write JSON, CSV and text files in Python cover

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=2 makes the file readable for humans and tidy in version control.
  • ensure_ascii=False keeps 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

ErrorUsual causeFix
FileNotFoundErrorWrong path or wrong working folderPrint Path.cwd() and use an absolute path
UnicodeDecodeErrorFile is not in the encoding Python guessedPass encoding="utf-8" (or the file's real encoding)
PermissionErrorFile is open in Excel or another programClose it, then retry
JSONDecodeErrorEmpty file, trailing comma, single quotesValidate 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.

Next reading on Sythra Articles

Keep reading

Related articles

Newsletter

Get new articles

Free essays on learning, Python, and ML — no account required. We’ll only email when there’s something worth reading.