In this post, we’ll teach you how to read and write files using Python.
First, we’ll describe how you can read data from a file. To do this, we need to access that file in read-only mode. The test file we’ll use in this example is a dictionary that contains in each line an English word and, separated from it by a space, its German translation. The file should be named dictionary.txt:
Spain Spanien
Germany Deutschland
Sweden Schweden
France Frankreich
Italy Italien
In the program, we want to prepare the data in this file so that we can conveniently access it later in a dictionary. As a little extra, we’ll extend the program to allow the user to ask the program for the translation of an English term.
Opening and Closing a File
First, the file must be opened for reading. For this purpose, we use the built-in open function. This function returns a so-called file object:
fobj = open("dictionary.txt", "r")
As the first parameter of open, we pass a string containing the path to the respective file. Note that both relative and absolute paths are allowed here. The second parameter is also a character string and specifies the mode in which the file is to be opened, where "r" stands for read and means that the file is opened for reading. We associate the file object returned by the function with the fobj reference. If the file doesn’t exist, a FileNotFoundError is generated:
Traceback (most recent call last):
File "dictionary.py", line 1, in <module>
fobj = open("dictionary.txt", "r")
FileNotFoundError: [Errno 2] No such file or directory: 'dictionary.txt'
Once open is called, the file object can be used to read data from the file. When the file has been read, it must be closed explicitly by calling the close method:
fobj.close()
After calling this method, no more data can be read from the file object.
The with Statement
In the previous section, you saw how you can open a file using the built-in open function and close it after using the close method of the opened file object:
fobj = open("dictionary.txt", "r")
# Do something with fobj
fobj.close()
The interplay of open and close is a typical pattern you will encounter again and again in various situations. In addition to file operations, network connections, for example, also represent situations in which a connection must first be established, then used, and finally closed.
The explicit use of open and close, as shown in the preceding example, bears the risk that due to a programming error or due to the omittance of error handling, the close method is not called and thus the file object is not closed. To make sure such errors won’t happen, you should use the with statement to open a file:
with open("dictionary.txt", "r") as fobj:
# Do something with fobj
pass
As soon as the control flow leaves the statement block indented below a with statement, the file object opened with the with statement is automatically closed. In particular, this also applies in the event of an error that hasn’t been handled.
Objects such as the file object that can be used in conjunction with a with statement are also referred to as context managers. At this point, it’s sufficient to know that the with statement ensures that the context manager is closed properly in every case.
Reading the File Content
In the next step, we want to read the file line by line. This is relatively simple as the file object can be iterated line by line. So we can use the old familiar for loop:
with open("dictionary.txt", "r") as fobj:
for line in fobj:
print(line)
In the for loop, we iterate over the file object line by line, with line each time referencing the contents of the current line. Currently, each line in the loop body is merely output. However, we want to build a dictionary in the program that contains the English terms as keys and the respective German terms as values after reading the file.
To do this, we first create an empty dictionary:
words = {}
Then the dictionary.txt file is opened for reading and iterated in a loop over all lines of the file:
with open("dictionary.txt", "r") as fobj:
for line in fobj:
assignment = line.split(" ")
if len(assignment) == 2: # consider only valid lines
words[assignment[0]] = assignment[1]
In the loop body, we now use the split method of a string to break the currently read line into two parts of a list: the part to the left of the space—that is, the English word—and the part to the right of the space—that is, the German word. In the next line of the loop body, a new entry is then created in the dictionary, with the assignment[0] key (the English word) and the assignment[1] value (the German word). Finally, we decide to tacitly skip a line if we could not extract exactly two components from it. We chose this type of error handling for didactic reasons to keep the program as simple as possible. In practice, you should ask yourself whether you should output the problematic lines or even terminate the program with an error message.
Now modify the preceding code once so that after closing the file object, the generated dictionary is output with print. The output will look like this:
{'Spain': 'Spanien\n', 'Germany': 'Deutschland\n', 'Sweden': 'Schweden\n',
'France': 'Frankreich\n', 'Italy': 'Italien\n'}
You can see that after each value there is a \n, which is the escape sequence for a line break. This is because a line break in Python is considered a character and thus part of the file contents. Thus, each line of a file is read entirely, including a possible line break at the end. Of course, the line break is only read if it really exists.
We don’t want to find the line break again in the final dictionary. For this reason, we call the strip method of the line string in each iteration. This removes all white space characters, including line breaks, at the beginning and end of the string:
words = {}
with open("dictionary.txt", "r") as fobj:
for line in fobj:
line = line.strip()
assignment = line.split(" ")
if len(assignment) == 2: # consider only valid lines
words[assignment[0]] = assignment[1]
Thus, the content of the file has been completely transferred to a dictionary. As a little extra, we now want to allow the user to send translation requests to the program. In the flow sequence, it should look like this:
Enter a word: Germany
The German word is: Deutschland
Enter a word: Italy
The German word is: Italien
Enter a word: Greece
The word is unknown
In the program, we read requests from the user in an infinite loop. The in operator enables us to check if the read word exists as a key in the dictionary. If so, the corresponding German translation is output. If the entered word doesn’t exist, an error message will be displayed:
words = {}
with open("dictionary.txt", "r") as fobj:
for line in fobj:
line = line.strip()
assignment = line.split(" ")
if len(assignment) == 2: # consider only valid lines
words[assignment[0]] = assignment[1]
while True:
word = input("Enter a word: ")
if word in words:
print("The German word is:", words[word])
else:
print("The word is unknown")
The sample program presented here is far from perfect, but it shows very nicely how file objects and also dictionaries can be used in a meaningful way. Feel free to expand the program. For example, you could allow the user to exit the program properly, offer translations in both directions, or allow the use of multiple source files.
Writing Data to a File
In the previous sections, we focused on reading files. The fact that it also works the other way around is the topic of this section. To open a file for writing, we also use the built-in open function. You’ll remember that this function expects a mode as second parameter, which had to be "r" for read in the last section. Similarly, "w" (for write) must be specified if the file is to be opened for writing. If the desired file already exists, it will be emptied. A file that doesn’t exist yet will be created:
fobj = open("output.txt", "w")
After all data has been written to the file, the file object must be closed by calling the close method:
fobj.close()
Also, when writing a file, you should use the with statement instead of explicitly using open and close:
with open("output.txt", "w") as fobj:
# Do something with fobj
pass
To write a string to the open file, you can call the write method of the file object. The following sample program is intended as a counterpart to the example from the last section. We assume that words references a dictionary containing English terms as keys and the German translations as values—for example:
words = {
"Germany": "Deutschland",
"Spain": "Spanien",
"Greece": "Griechenland"
}
So it’s a dictionary like that created by the sample program from the previous section:
with open("output.txt", "w") as fobj:
for engl in words:
fobj.write(f"{engl} {words[engl]}\n")
First, we open a file called output.txt for writing and then iterate over all keys of the words dictionary. In each iteration, a correspondingly formatted string is written to the file via fobj.write. Note that when writing a file, you must explicitly jump to a new line by outputting \n.
The file written by this example can be read again by the sample program from the last section.
Editor’s note: This post has been adapted from a section of the book Python 3: The Comprehensive Guide by Johannes Ernesti and Peter Kaiser. Johannes is a research scientist at DeepL. He is a graduate mathematician and received his doctorate in applied mathematics from the Karlsruhe Institute of Technology (KIT). Peter is a research scientist at DeepL. He has a degree in computer science and received a doctorate in humanoid robotics from the Karlsruhe Institute of Technology (KIT).
This post was originally published 4/2025.
Comments