How to Read and Write Text Files in Python
Everything a program holds in variables disappears when it stops running. To keep anything, such as a log, a to-do list, or a user's settings, you write it to a file, and the next time the program runs, you read it back. Python's built-in open() function handles both. Every example below was run in Python 3.13, and the output shown is what it printed.
1. The two arguments to open()
The official tutorial's Input and Output chapter explains that open() is most commonly used with two arguments: a filename and a mode. The mode is a short string that says how you will use the file:
| Mode | Meaning |
|---|---|
"r" |
Read only. This is the default if you leave mode out. |
"w" |
Write only. An existing file with the same name is erased. |
"a" |
Append. Anything written is added to the end. |
"r+" |
Read and write. |
That second row deserves a warning sign: opening an existing file with "w" wipes its contents immediately, before you write anything.
2. Writing a file safely with "with"
The tutorial recommends the with keyword whenever you work with files, because it closes the file properly when the block finishes, even if an error happens partway through. It also warns that calling write() without with or close() might leave data not completely written to disk.
with open("notes.txt", "w", encoding="utf-8") as f:
n = f.write("first line\n")
f.write("second line\n")
print(n)
print(f.closed)
Output:
11
True
A few things are happening here:
write()returns the number of characters written. "first line" plus the newline character\nis 11 characters.write()does not add a line break for you. The\nat the end of each string is what puts the next line on its own row.- After the
withblock ends,f.closedis True. The file was closed automatically. encoding="utf-8"states the text encoding explicitly. The tutorial notes UTF-8 is the default in text mode, but writing it out makes the intent clear.
3. Adding to a file instead of replacing it
To keep what is already there, open in append mode:
with open("notes.txt", "a", encoding="utf-8") as f:
f.write("third line\n")
4. Reading a file
The tutorial describes looping over the file object as memory efficient, fast, and simple. It reads one line at a time:
with open("notes.txt", encoding="utf-8") as f:
for line in f:
print(line, end="")
Output:
first line
second line
third line
Each line still ends with its \n, which is why end="" is used in print(). Without it, print() adds its own line break and you get blank lines in between.
If you want the lines as a clean list without the newline characters, strip them:
with open("notes.txt", encoding="utf-8") as f:
lines = [line.strip() for line in f]
print(lines)
Output:
['first line', 'second line', 'third line']
5. read() and readline()
Two other reading methods are useful to understand. readline() reads one line, keeping its \n. read() reads everything that is left. The tutorial notes that once the end of the file is reached, read() returns an empty string.
with open("notes.txt", encoding="utf-8") as f:
print(repr(f.readline()))
print(repr(f.read()))
print(repr(f.read()))
Output:
'first line\n'
'second line\nthird line\n'
''
repr() shows the hidden \n characters. The second read() returns '' because there is nothing left to read. An empty string is how Python tells you that you have reached the end.
6. Seeing "w" erase a file
To confirm the warning from the mode table, open the same file with "w" again:
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("only line now\n")
with open("notes.txt", encoding="utf-8") as f:
print(f.read(), end="")
Output:
only line now
The three earlier lines are gone. If you meant to add, use "a".
7. Errors you are likely to see
Opening a file that does not exist for reading raises FileNotFoundError, which the Python documentation on built-in exceptions describes as the error raised when a file or directory is requested but does not exist:
FileNotFoundError: [Errno 2] No such file or directory: 'missing.txt'
Check the spelling and remember that a plain filename is looked for in the folder you ran the script from.
Using a file after it has been closed raises the error the tutorial shows:
ValueError: I/O operation on closed file.
That usually means a line that reads the file was placed outside the indented with block.
8. Saving settings and lists with JSON
Text files store strings. The tutorial points out that saving numbers, lists and dictionaries by hand gets complicated, and recommends the standard json module instead.
import json
settings = {"theme": "dark", "font_size": 14, "recent": ["a.txt", "b.txt"]}
with open("settings.json", "w", encoding="utf-8") as f:
json.dump(settings, f)
with open("settings.json", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["font_size"] + 2)
print(loaded == settings)
Output:
16
True
json.dump() writes the dictionary as text, and json.load() turns it back into a dictionary, with 14 still a number you can do math with.
9. Key takeaways
open(filename, mode)opens a file;"r"reads,"w"writes and erases,"a"appends.- Always use
with open(...) as f:so the file is closed automatically. write()does not add line breaks; include\nyourself.- Loop over the file to read it line by line;
read()returns''at the end. - Use the
jsonmodule to save and load dictionaries and lists.