☰

File Handling in Python

File Handling in Python Tutorial: Open, Read, Write and Append

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.

What is File Handling in Python?

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.

How Python Handles Files

Every file operation follows the same three steps.

  1. Open the file, which gives you a file object. You say which file, and what you want to do with it.
  2. Work on it. Read from it, write to it, or move around inside it.
  3. Close it, so the data is saved and the file is released for other programs.

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.

Python File Handling Operations

Use of open()

The open function opens a file and returns a file object. Its basic form looks like this:

python
file_object = open(file_name, mode, buffering)

The name file_object is just a variable, so it is written with an underscore. Only the first argument is required.

Arguments of open
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:

python
try:
    open("test.txt", "w", 0)
except ValueError as e:
    print("ValueError:", e)
output
ValueError: can't have unbuffered text I/O

Modes for Opening a File

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.

File modes
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.

Text and binary letters
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

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.

python
f = open("test.txt", "w")
f.write("Writing in this file\n")
f.write("Second line\n")
f.write("Third line\n")
f.close()

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

Read mode opens an existing file for reading. It is the default, so open("test.txt") means the same as open("test.txt", "r").

python
f = open("test.txt", "r")
print(f.read())
f.close()
output
Writing in this file
Second line
Third line

Append Mode

Append mode keeps what is already in the file and adds the new text at the end.

python
f = open("test.txt", "a")
f.write("Adding this line to file\n")
f.close()
f = open("test.txt", "r")
print(f.read())
f.close()
output
Writing in this file
Second line
Third line
Adding this line to file

Create Mode

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.

python
import os

try:
    f = open("test.txt", "x")
except FileExistsError as e:
    print("FileExistsError:", e)
f = open("brand_new.txt", "x")
f.close()
print(os.path.exists("brand_new.txt"))
output
FileExistsError: [Errno 17] File exists: 'test.txt'
True

Read and Write Mode

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.

python
f = open("notes.txt", "w")
f.write("Fresh start\n")
f.close()
python
f = open("notes.txt", "r+")
print(repr(f.read()))
f.write("Added after reading\n")
f.seek(0)
print(repr(f.read()))
f.close()
output
'Fresh start\n'
'Fresh start\nAdded after reading\n'

The file held one line, Fresh start. The function repr shows the line breaks as \n so you can see them.

Text Mode and Binary Mode

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.

python
data = bytes([72, 101, 108, 108, 111])
f = open("data.bin", "wb")
f.write(data)
f.close()
f = open("data.bin", "rb")
print(f.read())
f.close()
f = open("data.bin", "rb+")
print(f.read(2))
f.close()
output
b'Hello'
b'He'

The mode rb+ reads and writes bytes. The b before the quotes in the output means the result is bytes and not text.

Use of read()

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.

python
with open("test.txt", "w") as f:
    f.write("Writing in this file\nSecond line\nThird line\n")
python
f = open("test.txt", "r")
print(repr(f.read()))
print(repr(f.read(4)))
f.close()
output
'Writing in this file\nSecond line\nThird line\n'
''

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.

python
f = open("test.txt", "r")
print(repr(f.read(4)))
print(f.tell())
f.seek(0)
print(repr(f.read(7)))
f.close()
output
'Writ'
4
'Writing'

The method tell gives the pointer position, and seek(0) moves it back to the start.

Use of readline() and readlines()

These are two different methods, and they are often mixed up.

read, readline and readlines
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
python
f = open("test.txt", "r")
print(repr(f.readline()))
print(repr(f.readline()))
f.close()
 
f = open("test.txt", "r")
lines = f.readlines()
print(lines)
print(len(lines))
f.close()
output
'Writing in this file\n'
'Second line\n'
['Writing in this file\n', 'Second line\n', 'Third line\n']
3

Loop Over a File Line by Line

For large files, do not read everything into memory. Loop over the file object, and Python gives you one line at a time.

python
f = open("test.txt", "r")
for number, line in enumerate(f, start=1):
    print(number, line.strip())
f.close()
output
1 Writing in this file
2 Second line
3 Third line

The strip method removes the line break at the end of each line, so print does not add a blank line.

Use of close()

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:

python
f = open("test.txt")
f.close()
try:
    f.read()
except ValueError as e:
    print("ValueError:", e)
output
ValueError: I/O operation on closed file.

The with Statement: The Better Way

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.

python
with open("notes.txt") as f:
    content = f.read()
print(f.closed)
print(content.splitlines())
output
True
['Fresh start', 'Added after reading']

The line print(f.closed) shows True, so the file was closed automatically after the block.

Use of write() and writelines()

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.

python
with open("list.txt", "w") as f:
    f.writelines(["apple\n", "banana\n", "cherry\n"])
with open("list.txt") as f:
    print([line.strip() for line in f])
output
['apple', 'banana', 'cherry']

Renaming a File

Renaming uses the os module. Here is the correct form, followed by what happens when the file is missing.

python
import os
 
os.rename("test.txt", "python_file.txt")
print(os.path.exists("test.txt"), os.path.exists("python_file.txt"))
try:
    os.rename("test.txt", "other.txt")
except FileNotFoundError as e:
    print("FileNotFoundError:", e)
output
False True
FileNotFoundError: [Errno 2] No such file or directory: 'test.txt' -> 'other.txt'

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.

Deleting a File and Checking If It Exists

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.

python
import os
 
os.remove("brand_new.txt")
print(sorted(os.listdir(".")))
for name in ("python_file.txt", "missing.txt"):
    if os.path.exists(name):
        print(name, "exists, size", os.path.getsize(name), "bytes")
    else:
        print(name, "does not exist")
output
['data.bin', 'list.txt', 'notes.txt', 'python_file.txt']
python_file.txt exists, size 44 bytes
missing.txt does not exist

The listing shows the other files we created earlier in this tutorial.

Handling File Errors

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.

python
try:
    open("missing.txt")
except FileNotFoundError:
    print("File not found")
output
File not found

Our exception handling tutorial covers try, except, else and finally in full.

Working With Hindi and Other Languages

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.

python
with open("hindi.txt", "w", encoding="utf-8") as f:
    f.write("नमस्ते Python\n")
with open("hindi.txt", encoding="utf-8") as f:
    print(f.read().strip())
output
नमस्ते Python

A Shorter Way With pathlib

For small text files, the pathlib module reads and writes in one line, and handles the open and close for you.

python
from pathlib import Path
 
p = Path("note.txt")
p.write_text("Short and simple\n")
print(p.read_text().strip())
output
Short and simple

Common Mistakes in Python File Handling

  • Using w when you meant a. Write mode erases the file, and the old data is gone. Use a to add.
  • Reading twice from the same open file. The second read gives an empty text, because the pointer is at the end. Use seek(0) or open the file again.
  • Forgetting to close. Use with open so you never need to.
  • Mixing up read, readline and readlines. One gives the whole text, one gives a line, and one gives a list.
  • Forgetting the line break. The write method does not add one.
  • Opening a missing file in r mode. It raises FileNotFoundError. Check with os.path.exists, or catch the error.
  • Forgetting the encoding for non English text. Add encoding="utf-8".
  • Curly quotes and missing spaces in code. Text copied from a web page can turn straight quotes into curly ones, and importos is a syntax error.

Quick Reference

File handling quick reference
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”)

Complete Script to Run Yourself

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.

python
import os
import tempfile
 
# Run everything inside a temporary folder so no real files are touched
workdir = tempfile.TemporaryDirectory()
os.chdir(workdir.name)

# 1. buffering 0 in text mode
try:
    open("test.txt", "w", 0)
except ValueError as e:
    print("ValueError:", e)

# 2. Write mode
f = open("test.txt", "w")
f.write("Writing in this file\n")
f.write("Second line\n")
f.write("Third line\n")
f.close()

# 3. Read mode
f = open("test.txt", "r")
print(f.read())
f.close()

# 4. Append mode
f = open("test.txt", "a")
f.write("Adding this line to file\n")
f.close()
f = open("test.txt", "r")
print(f.read())
f.close()

# 5. Create mode
try:
    f = open("test.txt", "x")
except FileExistsError as e:
    print("FileExistsError:", e)
f = open("brand_new.txt", "x")
f.close()
print(os.path.exists("brand_new.txt"))

# 6. Fresh file
f = open("notes.txt", "w")
f.write("Fresh start\n")
f.close()

# 7. r+ mode
f = open("notes.txt", "r+")
print(repr(f.read()))
f.write("Added after reading\n")
f.seek(0)
print(repr(f.read()))
f.close()

# 8. Binary mode
data = bytes([72, 101, 108, 108, 111])
f = open("data.bin", "wb")
f.write(data)
f.close()
f = open("data.bin", "rb")
print(f.read())
f.close()
f = open("data.bin", "rb+")
print(f.read(2))
f.close()

# 9. Reset file
with open("test.txt", "w") as f:
    f.write("Writing in this file\nSecond line\nThird line\n")

# 10. read twice
f = open("test.txt", "r")
print(repr(f.read()))
print(repr(f.read(4)))
f.close()

# 11. tell and seek
f = open("test.txt", "r")
print(repr(f.read(4)))
print(f.tell())
f.seek(0)
print(repr(f.read(7)))
f.close()

# 12. readline and readlines
f = open("test.txt", "r")
print(repr(f.readline()))
print(repr(f.readline()))
f.close()
 
f = open("test.txt", "r")
lines = f.readlines()
print(lines)
print(len(lines))
f.close()

# 13. loop
f = open("test.txt", "r")
for number, line in enumerate(f, start=1):
    print(number, line.strip())
f.close()

# 14. closed file
f = open("test.txt")
f.close()
try:
    f.read()
except ValueError as e:
    print("ValueError:", e)

# 15. with
with open("notes.txt") as f:
    content = f.read()
print(f.closed)
print(content.splitlines())

# 16. writelines
with open("list.txt", "w") as f:
    f.writelines(["apple\n", "banana\n", "cherry\n"])
with open("list.txt") as f:
    print([line.strip() for line in f])

# 17. rename
os.rename("test.txt", "python_file.txt")
print(os.path.exists("test.txt"), os.path.exists("python_file.txt"))
try:
    os.rename("test.txt", "other.txt")
except FileNotFoundError as e:
    print("FileNotFoundError:", e)

# 18. remove and exists
os.remove("brand_new.txt")
print(sorted(os.listdir(".")))
for name in ("python_file.txt", "missing.txt"):
    if os.path.exists(name):
        print(name, "exists, size", os.path.getsize(name), "bytes")
    else:
        print(name, "does not exist")

# 19. file error
try:
    open("missing.txt")
except FileNotFoundError:
    print("File not found")

# 20. hindi
with open("hindi.txt", "w", encoding="utf-8") as f:
    f.write("नमस्ते Python\n")
with open("hindi.txt", encoding="utf-8") as f:
    print(f.read().strip())

# 21. pathlib
from pathlib import Path
 
p = Path("note.txt")
p.write_text("Short and simple\n")
print(p.read_text().strip())

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.

Popular Tags:

File Handling in Python Tutorial File Handling in Python Tutorial with Example online course to learn python online training on python Python File Handling Operations python training course online python training online