Closing a Text File
Every book says “always close your files”, and every student ignores it, because a program that forgets usually works anyway. Here is the reason it matters — and it is not manners. It is that the words you wrote are not in the file yet.
1close() does two jobs
f.close() takes no arguments and gives nothing back. It ends the connection the handle stood for, and on the way out it does two things:
Writing to a disk is slow, so Python does not do it a letter at a time. write() puts the characters in a buffer in RAM, and the buffer is emptied onto the disk later — at the latest, when the file is closed.
The operating system lets a program hold only so many files open at once, and on Windows an open file can be locked against other programs. close() releases both.
2The buffer, made visible
This program writes to a file and then — before closing it — opens the same file again through a second handle and reads it. That second handle is looking at the disk:
f = open('draft.txt', 'w')
f.write('Half a line')
check = open('draft.txt', 'r')
print('Before close, the file holds:', repr(check.read()))
check.close()
f.close()
check = open('draft.txt', 'r')
print('After close, the file holds:', repr(check.read()))
check.close()Before close, the file holds: '' After close, the file holds: 'Half a line'
Step through the program. Watch the disk — it does not change until the last line.
check.read() → ''The file exists and is empty. 'w' emptied it on the way in.
write() had already run, and the file on the disk was still empty. The characters were sitting in RAM. close() is what put them in the file — which is why a program that skips it can leave a file with nothing in it.There is a way to empty the buffer without closing the file: flush(). It is rarely needed, but it proves what the buffer is.
f = open('draft.txt', 'w')
f.write('Half a line')
f.flush()
check = open('draft.txt', 'r')
print('After flush, the file holds:', repr(check.read()))
check.close()
f.close()After flush, the file holds: 'Half a line'
3A closed handle still exists
close() does not delete the variable. f is still there, still a file object, and f.closed is now True. What it can no longer do is touch the file:
f = open('notes.txt', 'r')
f.close()
print(f.read())Traceback (most recent call last):
File "too_late.py", line 3, in <module>
print(f.read())
^^^^^^^^
ValueError: I/O operation on closed file.ValueError: I/O operation on closed file. means the program closed the file and then tried to use it — usually because close() was written inside a loop that then went round again. Closing twice, though, is harmless: a second close() on an already-closed file does nothing at all.4What actually goes wrong if you forget
The buffer never reached the disk. This is the one that costs real work, and it happens exactly when the program crashed — which is when you most wanted the data.
On Windows another program — Excel, Notepad, your own program's next run — may be refused access while your handle is open.
A loop that opens a thousand files and closes none will run out. The operating system caps how many one program may hold.
A file-handling answer without close() (or a with block) is not a complete program, and it is marked as such.
5The problem with writing close() at the end
Look at where close() sits in this program. It is the last line — so if anything above it raises an exception, it never runs:
try:
f = open('notes.txt', 'r')
print('the file is open')
print(10 / 0)
f.close()
except ZeroDivisionError:
print('The program crashed before close() ran.')
print('closed?', f.closed)the file is open The program crashed before close() ran. closed? False
The fix you already know is finally, from the Exception Handling chapter. finally runs whatever happens, so the file is closed either way:
f = open('notes.txt', 'r')
try:
print('the file is open')
print(10 / 0)
except ZeroDivisionError:
print('Something went wrong.')
finally:
f.close()
print('closed?', f.closed)the file is open Something went wrong. closed? True
with.6Try it
Delete the f.close() line below and run it. The 💾 saved.txt pill above the output tells you what the file really holds.
7Recap
No arguments, no answer. It ends the connection the handle stood for.
write() puts characters in RAM. Until they are flushed, the file on the disk does not have them.
Other programs can reach it again, and your program is not holding a handle it no longer needs.
f still exists and f.closed is True. Reading or writing through it raises ValueError.
An exception above it means close() never runs. finally fixes that — and with does it for you.
A second close() on a closed file does nothing.
- 1
Write a line into a file, and before closing it, open the same file again and print what is inside.
Hint · Two handles at once. The second one reads the disk.
- 2
Close a file and then call
f.read()on it.Hint · ValueError: I/O operation on closed file.
- 3
Print
f.closedbefore and afterf.close(), then callclose()a second time.Hint · False, True — and the second close() is quietly ignored.
- 4
Rewrite one of your file programs so the
close()sits in afinallyblock.Hint · open() goes above the try; only the work goes inside it.
A program writes to a file and is stopped before close() runs. What is usually in the file?
What does f.close() give back?
What is the error when a program reads a file it has already closed?
Where should close() go so that it runs even when the program crashes?