Reading and writing files
Notes that outlive the program: open a file, write to it, read it back — and close it the tidy way with with.
The playground has a small disk
Variables live and die with the program. A file stays — on this page it lives in a small disk the playground keeps while the tab is open, and on a real machine it would be the folder next to your script.
open("notes.txt", "w") opens a file for writing. The "w" means write: the file is created if it is missing, and emptied if it already exists. open("notes.txt", "r") opens it for reading, where the text comes back exactly as it went in.
Writing two lines, then reading them
with open("notes.txt", "w") as note:
note.write("Buy flour\n")
note.write("Feed the starter\n")
with open("notes.txt", "r") as note:
print(note.read())with closes the file for you
A file has to be closed when you are finished with it — the writing is only guaranteed to be complete once it is. with does that for you: the block ends, the file is closed, and the finished text is on the disk.
It also closes the file when something goes wrong inside the block, which is the part that makes it worth the extra words. The long-handed way is to call close() yourself; forgetting it is how a program writes half a file.
Writing replaces; appending adds
The mode decides what happens to what is already there. "w" starts from nothing every time the program runs, which is why re-running the snippet above never gives four lines.
"a" appends: the new text goes after whatever the file already holds. That is the mode for a log, where each run adds its own entry rather than erasing yesterday’s.
Two lines on the disk
The program writes one line and stops. Write a second line into the file, then open it for reading and print everything it holds.
The end of a line is a character of its own — written as \n. A file built from writes will run its lines together unless you end each one with it.
Reading gives you one string
read() returns the whole file as a single string, newlines included. That is why a printed file can look double-spaced: the file already ends each line with \n, and print adds another. line.strip() removes the newline and surrounding spaces when you want the text alone.
A file object is also a sequence of lines, so for line in note: hands you one line per turn without loading the whole thing into a name first. Each line still carries its \n; strip it before comparing or printing it in a sentence.
The mode is a promise about the old contents
The mode you pass to open decides what happens before your first write. "w" truncates, "a" moves to the end, "r" refuses to create anything, and "x" refuses to overwrite.
Choosing the mode is choosing a promise: a log appends, a report replaces, a read expects the file to exist. When a program seems to lose data, check the mode before checking the writes.
The path is relative to where the program runs
open("notes.txt") does not mean “next to this file” in the abstract; it means “relative to the directory the program was started in”. On a real machine those can differ, which is why a script that works from its own folder can fail when launched from elsewhere. An absolute path removes the doubt.
The playground gives every program the same small working directory, so a bare filename is enough here. When you move code to a computer, decide deliberately whether the path should be relative or absolute, and keep data files out of the folder that holds the code.
Reading is not the same as loading
read() loads the whole file into one string. That is fine for a note and wasteful for a log with a hundred thousand lines. Iterating over the file object reads one line at a time, so memory holds a line rather than a document.
The loop form also makes the newline visible: each line arrives with its \n, and the last line may or may not have one depending on how it was written. strip() makes both cases look the same, which is usually what a comparison wants. Printing a line that still ends in a newline is how output acquires a blank line between every pair.
Three file mistakes: writing several values with one write call and no \n runs them together; opening with "w" when you meant "a" erases the file first; and reading a file before the write has been closed can miss the new text, because it is still buffered.
Try these next
- Write three lines to a file, then print each line with
for line in file:and strip the newline. - Open the same file with
"a", add one line, and check the earlier lines are still there. - Print a file with
read()and then with a loop, and compare the spacing.
A log that keeps yesterday
Run it once, then add a third log entry and run it again — the file should grow rather than start over.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
What does opening a file with mode "w" do?
