Read and Write Files in Python: Text, CSV and JSON

Python for Beginners: Learn to Code with Real Projects · Functions, Text and Files · 6 min read · Updated

Files in and out of Python

  1. Data is stored in files on disk: plain text, CSV spreadsheets or JSON.
  2. The with open statement opens the file and closes it again, even if an error happens.
  3. Python turns the content into text, rows or dictionaries that you can work with.
  4. Your results can be written to a new file, using write mode, or csv and json tools.

Data lives in files: notes, spreadsheets exported as CSV, settings in JSON. Programs that read and write files can clean data, make reports and keep information between runs. In this lesson you learn the three formats you will meet most: plain text, CSV and JSON. The program below creates its own files in a temporary folder and removes them at the end, so you can run it safely.

The with statement

open(path) gives you a file object. When you finish, the file must be closed, or data can be lost. The safest way is with open(...) as f:. When the indented block ends, even if an error happens, Python closes the file for you. Always give encoding="utf-8" for text, so names and symbols in any language work the same on every computer. The modes are "r" to read (the default), "w" to write and replace everything, and "a" to add at the end.

pathlib: paths that work everywhere

The Path class from pathlib builds file paths in a way that works on Windows, macOS and Linux. folder / "notes.txt" joins parts of a path with the right separator. It also has handy methods: .exists(), .mkdir(), .read_text(), .write_text(), .iterdir() and .name. Prefer Path to typing slashes and backslashes by hand.

import csv
import json
from pathlib import Path

folder = Path("data_demo")
folder.mkdir(exist_ok=True)

# Text file
notes = folder / "notes.txt"
notes.write_text("first line\nsecond line\n", encoding="utf-8")
with open(notes, encoding="utf-8") as f:
    for number, line in enumerate(f, start=1):
        print(number, line.strip())

# Append
with open(notes, "a", encoding="utf-8") as f:
    f.write("third line\n")
print(len(notes.read_text(encoding="utf-8").splitlines()), "lines now")

# CSV
rows = [
    {"date": "2026-01-05", "category": "Food", "amount": 250},
    {"date": "2026-01-06", "category": "Travel", "amount": 120},
]
csv_file = folder / "expenses.csv"
with open(csv_file, "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["date", "category", "amount"])
    writer.writeheader()
    writer.writerows(rows)

with open(csv_file, newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        print(row["category"], int(row["amount"]))

# JSON
settings = {"currency": "INR", "budget": 5000, "tags": ["home", "work"]}
json_file = folder / "settings.json"
json_file.write_text(json.dumps(settings, indent=2), encoding="utf-8")
loaded = json.loads(json_file.read_text(encoding="utf-8"))
print(loaded["budget"], loaded["tags"])

print(sorted(p.name for p in folder.iterdir()))
print(Path("missing.txt").exists())

import shutil
shutil.rmtree(folder)
1 first line
2 second line
3 lines now
Food 250
Travel 120
5000 ['home', 'work']
['expenses.csv', 'notes.txt', 'settings.json']
False

Understanding the example

  • Text: write_text creates the file. Looping over a file object with for line in f gives one line at a time, which is good for big files, and line.strip() removes the line break at the end.
  • Append: mode "a" added the third line. The program then counted 3 lines.
  • CSV: CSV means comma-separated values, the plain-text form of a spreadsheet. csv.DictWriter writes rows from dictionaries, and csv.DictReader reads each row as a dictionary with the column names as keys. Open CSV files with newline="", as the documentation says. Everything read from a CSV is text, so convert numbers yourself, as in int(row["amount"]).
  • JSON: json.dumps turns Python data into JSON text, indent=2 makes it readable, and json.loads turns it back into dictionaries and lists. JSON handles numbers, text, lists, dictionaries, true, false and null (Python's None). It cannot store everything, for example dates, which you must convert to text.
  • Cleaning up: shutil.rmtree(folder) deletes a folder and everything inside it. Be careful with it: there is no recycle bin.

Read a whole file or line by line?

  • f.read() returns everything as one text. Fine for small files.
  • for line in f: handles one line at a time and uses little memory. Use it for large files.
  • f.readlines() gives a list of all lines.

Where does Python look for a file?

A relative path such as "notes.txt" is relative to the current folder of the terminal, not to the folder where your script is stored. If you run the script from another folder, the file may not be found. When your script needs to find a file that sits next to it, build the path from the script's location: Path(__file__).parent / "notes.txt". You will do this in lesson 13.

Safety with files

  • Opening a file with "w" erases the old content at once. Use "a" to add, or check with exists() first.
  • Do not delete or overwrite files from a program until you have tested it on copies.
  • Never build file paths from text typed by an untrusted user without checking, because input like .. can climb out of your folder.
  • Keep secrets such as passwords out of files that you share or upload.

Your task

  1. Write a program that saves three lines of your own into notes.txt, then reads and prints them with line numbers.
  2. Create a CSV file students.csv with columns name and marks and four rows. Read it, convert marks to numbers and print the average.
  3. Save a dictionary of your settings as settings.json and load it again. Print one value.
  4. Print the names of the files in the current folder using Path(".").iterdir().

How to check it worked

  • The notes are printed in order with numbers 1 to 3.
  • The average of your marks matches a calculation by hand.
  • The loaded JSON value is the same as the one you saved.

Frequently asked questions

Why use with open instead of just open?

with closes the file automatically, even when an error happens. Without it, you must remember to call close(), and data may be lost if you forget.

Why is everything I read from a CSV text?

CSV is plain text, so Python cannot know which columns are numbers. Convert them yourself with int() or float().