Opening & Closing a CSV File
There is no new function in this lesson. A CSV is a text file, so you open it with the open() you learned in the Text Files chapter and close it with the same close(). What is worth a lesson is the two places students go wrong: reaching for a binary mode out of habit, and leaving out the one extra argument.
1The call, in full
f = open('marks.csv', 'w', newline='')A name, or a whole path. Exactly as in every other open().
'r', 'w' or 'a'. No 'b' anywhere — a CSV is a text file.
Stops an extra blank line appearing between the rows.
The first two are old news. The third one is new, and this lesson only asks you to type it — the reason it is there gets a lesson of its own once you have seen the file it repairs.
newline='' in every open() call that involves a CSV file, reading or writing. It never does harm, and leaving it out causes a bug that is hard to spot. The why is two lessons away.2The three modes you need
| Mode | If the file exists | If it does not | Used for |
|---|---|---|---|
| 'r' | opens it for reading | FileNotFoundError | reading records |
| 'w' | empties it completely | creates it | creating a file from scratch |
| 'a' | keeps it, writes at the end | creates it | adding records to an existing file |
open('marks.csv', 'w') runs, every record already in marks.csv is gone — even if the program crashes on the next line and writes nothing. When you want to add a record to a file that already has some, 'a' is the mode, not 'w'.3Never 'rb' or 'wb'
You have just spent a chapter adding b to every mode. Do not add it here. A CSV file holds text, so it is opened in text mode, and the error you get for forgetting has nothing in it about modes:
import csv
f = open('marks.csv', 'wb')
w = csv.writer(f)
w.writerow(['Ravi', 78])
f.close()Traceback (most recent call last):
File "wrong_mode.py", line 5, in <module>
w.writerow(['Ravi', 78])
TypeError: a bytes-like object is required, not 'str'Read the message from the file's point of view and it makes sense: 'wb' told the file to accept bytes, and the csv writer handed it a string. The fix is on line 3, three lines above where Python stopped.
open('marks.dat', 'wb')pickle writes bytes, so the file must accept bytes.
open('marks.csv', 'w', newline='')The csv writer writes text, so the file must accept text.
4Closing it — and what happens if you do not
close() is called on the file. Not on the writer, not on the reader — those have no close() and need none.
import csv
f = open('marks.csv', 'w', newline='')
w = csv.writer(f)
w.writerow(['Ravi', 78])
f.close() # correct — close the file
# w.close() # wrong — a writer has no close()Everything the closing lesson taught still applies, because it is the same file object underneath. What writerow() writes sits in a buffer in memory; close() is what pushes it onto the disk. Use the writer after that and Python refuses:
import csv
f = open('marks.csv', 'w', newline='')
w = csv.writer(f)
f.close()
w.writerow(['Ravi', 78])Traceback (most recent call last):
File "too_late.py", line 7, in <module>
w.writerow(['Ravi', 78])
ValueError: I/O operation on closed file.5Letting with close it
The with clause works here exactly as it does for a text file, and for the same reason: the file is closed when the block ends, even if something goes wrong inside it.
import csv
with open('marks.csv', 'r', newline='') as f:
for row in csv.reader(f):
print(row)
print('closed?', f.closed)['Roll', 'Name', 'Marks'] ['1', 'Ravi', '78'] ['2', 'Meera', '91'] ['3', 'Amit', '65'] closed? True
csv.reader(f) line goes inside the block. It needs an open file, and outside the block there is not one.6When the file is not there
Opening a CSV for reading that does not exist fails on the open() line, before the csv module is involved at all:
import csv
f = open('results.csv', 'r', newline='')
r = csv.reader(f)
for row in r:
print(row)
f.close()Traceback (most recent call last):
File "missing.py", line 3, in <module>
f = open('results.csv', 'r', newline='')
FileNotFoundError: [Errno 2] No such file or directory: 'results.csv'The repair is the same one the paths lesson gave you — wrap it in try:
7The whole round trip
Write a file and read it back, with nothing in it you have not met. Every line after import csv is either an open(), a close(), or one of the two new objects:
f.close() in the middle. The same handle cannot be used for both jobs — it was opened in 'w' — and the rows may still be sitting in the buffer until that close runs.8Recap
The same function, the same first two arguments. There is no csv.open().
'r', 'w', 'a'. Adding a b gives TypeError: a bytes-like object is required, not 'str'.
In every open() that touches a CSV. Two lessons from now you will see what it repairs.
Opening in 'w' wipes the file the instant it runs, records and header alike.
f.close(), never w.close(). Using a writer afterwards raises ValueError: I/O operation on closed file.
Put the csv.reader() or csv.writer() line inside the block, where the file is open.
- 1
Open a CSV in
'wb'on purpose and read the error. Note which line Python blames.Hint · It blames the
writerow(), but the mistake is up on theopen()line. - 2
Call
f.close()and thenw.writerow().Hint · ValueError: I/O operation on closed file.
- 3
Write the round-trip program using
withfor both halves.Hint · Two blocks, one after the other. No close() anywhere.
- 4
Open an existing CSV in
'w', write nothing, close it, and look at the file.Hint · Empty. That is what 'w' does the moment it opens.
Which mode should you use to open a CSV file for writing?
What do you call close() on?
You want to add one record to a CSV that already holds fifty. Which mode?
Where should the csv.reader(f) line go when you use a with block?