Every variable in your program lives in memory, and memory is wiped the moment the program ends. A user fills in a form, a script calculates a result, a game records a high score, and when the window closes, all of it is gone. To keep anything, a program has to write it to a file.
File handling is how Python reads from files and writes to them. It lets you store results, load data, keep logs, and share information between programs. A text file of customer names, a CSV of sales, a log of errors and a saved configuration are all handled the same way. Once you know the basic steps, you can work with any of them.
In this tutorial, we cover the open function and its modes, and then read, readline and readlines, write, append, close and the with statement. We go on to binary files, moving around a file with seek and tell, renaming and deleting files, checking if a file exists, and the errors you will meet. Every example was run on Python 3.13, and the real output is shown. We end with the mistakes beginners make most often and a quick reference.
File handling means creating, opening, reading, writing, changing and closing files from inside a Python program. A file stores data on your disk, so it stays after the program stops, and the next run of the program can read it back.
Every file operation follows the same three steps.
The file object is the link between your program and the file on disk. All the methods in this tutorial, such as read and write, belong to it.
The open function opens a file and returns a file object. Its basic form looks like this:
The name file_object is just a variable, so it is written with an underscore. Only the first argument is required.
| Argument | What it means |
|---|---|
| file_name | The name or path of the file, as text, such as “test.txt” |
| mode | A short text that says what you want to do, such as “r” to read. The default is “r” |
| buffering | Optional. The default is minus 1, which means the system chooses. A value of 0 turns buffering off, and that is only allowed for binary files |
The mode is text, and the default for buffering is minus 1. In text mode, a value of 0 gives this error:
The mode decides what you can do with the file, and what happens if it exists or does not. Four letters set the main action, and one more adds detail.
| Mode | Name | What it does | If the file is missing |
|---|---|---|---|
| “r” | Read | Opens for reading. This is the default | FileNotFoundError |
| “w” | Write | Opens for writing and erases the old content | Creates the file |
| “a” | Append | Opens for writing at the end, and keeps the old content | Creates the file |
| “x” | Create | Creates a new file for writing | Creates the file. If it already exists, raises FileExistsError |
| “r+” | Read and write | Reads and writes, without erasing | FileNotFoundError |
Two more letters can be added to any of these.
| Letter | Name | What it does |
|---|---|---|
| t | Text | Works with text. This is the default, so “r” and “rt” are the same |
| b | Binary | Works with raw bytes, as in images and PDFs. Used as “rb”, “wb” and “rb+” |
Text and binary are not modes that create files. They only change how the file is read or written, and “rt” and “rb” only read. Pay attention to two details in the table above. Write mode erases the old content, and create mode raises an error if the file already exists. Both are shown next.
Write mode creates the file if it is not there. If it is there, it erases everything inside first. This is the most common way to lose data by accident.
The write method does not add a new line for you. We put \n at the end of each line, which means a line break. The method gives no output, but the file now holds three lines.
Read mode opens an existing file for reading. It is the default, so open("test.txt") means the same as open("test.txt", "r").
Append mode keeps what is already in the file and adds the new text at the end.
Create mode makes a new file, and refuses to touch one that already exists. It is the safe choice when you must not overwrite anything. The second part of the example creates a new file, which we delete later.
The mode r+ lets you read and write in the same file, and it does not erase the content. The writing starts wherever the pointer is. After a full read, the pointer is at the end, so the new text is added there. First we make a small file, which also shows that write mode erases the old content.
The file held one line, Fresh start. The function repr shows the line breaks as \n so you can see them.
Text mode is the default. Python turns the bytes in the file into text for you. Binary mode gives you the raw bytes, and you need it for images, audio, PDFs and any file that is not plain text. Add the letter b to the mode.
The mode rb+ reads and writes bytes. The b before the quotes in the output means the result is bytes and not text.
Without a number, read returns the whole file as one text. With a number, it returns that many characters. A common mistake is to call it twice on the same open file and expect the second call to give the first four characters. First, we write the three lines again, so the next examples are easy to follow.
The second call returns an empty text, because the first call already read to the end. A file keeps a position, called the pointer, and every read moves it forward. To get the first four characters, read them on a fresh file object, or move the pointer back to the start with seek.
The method tell gives the pointer position, and seek(0) moves it back to the start.
These are two different methods, and they are often mixed up.
| Method | What it returns |
|---|---|
| read() | The whole file as one text |
| readline() | One line, including its line break. Each call gives the next line |
| readlines() | A list of all the lines |
For large files, do not read everything into memory. Loop over the file object, and Python gives you one line at a time.
The strip method removes the line break at the end of each line, so print does not add a blank line.
The close method saves any waiting data and releases the file. If you forget to close a file you have written to, some of your data may never reach the disk. A closed file cannot be read again:
Writing close by hand is easy to forget, and it is skipped when an error happens. The with statement fixes this. It closes the file for you when the block ends, even if there is an error. Most Python programmers use this form all the time.
The line print(f.closed) shows True, so the file was closed automatically after the block.
The write method takes one text. To write several lines at once, use writelines with a list. It does not add line breaks either, so put them in the list.
Renaming uses the os module. Here is the correct form, followed by what happens when the file is missing.
The first rename works, so test.txt is gone and python_file.txt exists. The second rename fails, because test.txt is no longer there.
Use os.remove to delete a file, and os.path.exists to check first. Deleting is permanent, because the file does not go to the recycle bin.
The listing shows the other files we created earlier in this tutorial.
Files go wrong often, since a file can be missing, locked or without permission. Wrap the open call in try and except so the program can respond.
Our exception handling tutorial covers try, except, else and finally in full.
If a file holds text that is not plain English, such as Hindi, Bengali or Arabic, give the encoding when you open it. The standard choice is utf-8. Without it, the result can depend on your computer, and the text can come out broken on another.
For small text files, the pathlib module reads and writes in one line, and handles the open and close for you.
a to add.seek(0) or open the file again.with open so you never need to.write method does not add one.FileNotFoundError. Check with os.path.exists, or catch the error.encoding="utf-8".importos is a syntax error.| Task | Code |
|---|---|
| Read the whole file | with open(“a.txt”) as f: text = f.read() |
| Read line by line | for line in f: |
| Get all lines as a list | f.readlines() |
| Write, erasing old content | open(“a.txt”, “w”) |
| Add to the end | open(“a.txt”, “a”) |
| Create only if new | open(“a.txt”, “x”) |
| Rename | os.rename(“old”, “new”) |
| Delete | os.remove(“a.txt”) |
| Check if it exists | os.path.exists(“a.txt”) |
Here is the full script used to produce every output on this page, in the same order. It works inside a temporary folder, so it will not touch any of your real files. Copy it into a file, run it with Python 3, and compare the results.
File handling comes down to a short habit: open the file with the right mode, do your work, and let the with statement close it. Choose w, a and x with care, remember that the pointer moves as you read, and always handle the case where the file is missing. Run the script above, change the modes, and watch what the files do. Then try reading a real CSV file, and look at the csv and json modules for structured data.