Files and errorsChapter 85 of 114
CSV Files
Read and write comma-separated data without breaking on quoted commas.
Do not split on commas
A real CSV can hold commas inside quoted fields, and splitting by hand cuts them in half:
line = 'Ada,"maths, and computing",1815'
print(line.split(","))Output
['Ada', '"maths', ' and computing"', '1815']
Three fields became four. The csv module knows the rules:
import csv
import io
line = 'Ada,"maths, and computing",1815'
print(next(csv.reader(io.StringIO(line))))Output
['Ada', 'maths, and computing', '1815']
Writing
import csv
rows = [["name", "born"], ["Ada", 1815], ["Grace", 1906]]
with open("people.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerows(rows)
with open("people.csv", encoding="utf-8") as f:
print(f.read().strip())Output
name,born Ada,1815 Grace,1906
Reading rows
import csv
with open("people.csv", "w", encoding="utf-8", newline="") as f:
csv.writer(f).writerows([["name", "born"], ["Ada", 1815]])
with open("people.csv", encoding="utf-8", newline="") as f:
for row in csv.reader(f):
print(row)Output
['name', 'born'] ['Ada', '1815']
Note '1815' is a string. CSV has no types — everything comes back as text, and converting is your job.
DictReader is usually what you want
It uses the header row, so you read by column name rather than by position:
import csv
with open("people.csv", "w", encoding="utf-8", newline="") as f:
csv.writer(f).writerows([["name", "born"], ["Ada", 1815], ["Grace", 1906]])
with open("people.csv", encoding="utf-8", newline="") as f:
for row in csv.DictReader(f):
print(row["name"], int(row["born"]) + 100)Output
Ada 1915 Grace 2006
Now inserting a column in the file cannot break your code.
DictWriter
import csv
people = [
{"name": "Ada", "born": 1815},
{"name": "Grace", "born": 1906},
]
with open("people.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["name", "born"])
writer.writeheader()
writer.writerows(people)
with open("people.csv", encoding="utf-8") as f:
print(f.read().strip())Output
name,born Ada,1815 Grace,1906
fieldnames fixes the column order and, by default, a key not in that list raises rather than being silently dropped.
Other separators
import csv
with open("data.tsv", "w", encoding="utf-8", newline="") as f:
csv.writer(f, delimiter="\t").writerow(["a", "b"])
with open("data.tsv", encoding="utf-8", newline="") as f:
print(next(csv.reader(f, delimiter="\t")))Output
['a', 'b']
Semicolons are common in countries where the comma is the decimal separator, so delimiter=";" comes up often with spreadsheet exports.
Large files
A reader is an iterator, so it never loads the whole file:
import csv
with open("big.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerow(["n"])
writer.writerows([[i] for i in range(1000)])
total = 0
with open("big.csv", encoding="utf-8", newline="") as f:
for row in csv.DictReader(f):
total += int(row["n"])
print(total)Output
499500
That works the same on a file of ten million rows.
Test yourself
2 questionsWhy not split a CSV line on commas yourself?
Show the answer
A quoted field can contain a comma — The csv module knows the quoting rules. Splitting by hand cuts a quoted field in half.
Why pass newline="" when opening a CSV?
Show the answer
Otherwise line endings are translated and rows come out blank — Pass it for reading too, so quoted fields containing newlines survive.
Context Managers
Guarantee that cleanup happens, even when something goes wrong.