Python File Handling: How to Read and Write Files

Most real-world applications need a reliable way to save information and retrieve it later. File handing provides this capability by allowing your Python program to read data from files and write data back to them, such as text files, logs, or configuration files.

In this guide, you will learn everything about Python file handling, from opening and reading files to writing data, handling errors, and following best practices — with clear explanations and examples.

Opening Files in Python

To work with files, you must first open it using the built-in open() function.

Basic Syntax

file = open(filename, mode, encoding=None)

Parameters

filename: The path to your file (relative or absolute)

mode: Determines what you can do with the file (read, write, append)

encoding: How text is translated to/from bytes (optional, recommended to specify)

Example: Opening file demo.txt file

First let’s create a text file named demo.txt using VS Code or any text editor (Notepad on Windows, TextEdit on macOS, or Nano/Vim on Linux). Write anything you like in the file, and make sure it is saved in the same directory as your Python script. If it is in a different location, you will need to provide the correct file path when opening it in Python.

Here is a directory tree showing both files in the same folder:

project_folder/
├── app.py
└── demo.txt

For example, my demo.txt file contains:

Hello, from the demo.txt file!

Now let’s open the demo.txt file:

# Opening a file
file = open("demo.txt", "r")

File Opening Modes

Python supports various file modes that determine how you interact with a file.

ModeDescriptionFile Pointer Position
'r'Read (Default)Beginning of file
'w'Write (creates or overwrites)Beginning of file
'a'Append (creates or adds to end)End of file
'x'Create new file (fails if exists)Beginning of file
'r+'Read and write Beginning of file
'w+'Read and write (overwrite/truncate)Beginning of file
'a+'Read and append End of file
'rb'Read binaryBeginning of file
'wb'Write binary Beginning of file
'ab'Append binaryEnd of file

The Modern Way: Using the with Statement to Open Files

This is the modern and recommended way to open a file in Python. It ensures that the file is properly closed, even if an error occurs while the file is being processed.

Here’s how you would open a file using the with statement:

# Using the 'with' statement to open a file 
with open('demo.txt', 'r') as file:
    print("File opened successfully")

Output:

File opened successfully

With this approach, the file will be automatically closed when the block inside the with statement is completed, so there is no need to explicitly call the close() method. It makes your code clearner and ensures proper resource management.

Reading Files in Python

There are several ways to read data in Python, depending on the file size and your specific needs.

(1) The read() Method

The read() method reads the entire contents of a file as a single string and is best suited for small files.

Example: Reading content of demo.txt file

First let’s open the file and read its contents using the traditional approach, and then see how to accomplish the same task using the modern with statement.

# Opening a file
file = open("demo.txt", "r")

# Reading the contents of the file
content = file.read()
print(content)

# Always remember to close the file after you're done
file.close()

Output:

Hello, from the demo.txt file!

In this example, we open the file demo.txt in read mode ('r') using the open() method. The content of the file is then read into the variable content and printed to the screen.

However, after reading the content, it is important to explicitly close the file using file.close() to free up system resources, since leaving files open can waste memory and cause unexpected issues.

Now let’s see how to accomplish the same task using the modern with statement:

# Using 'with' statement to open the file 
with open('demo.txt', 'r') as file:
    # Reading the contents of the file
    content = file.read()
    print(content)

In this example, we open the file demo.txt in read mode using a with statement, which ensures that the file is properly closed after the block of code is executed, even if an error occurs. It automatically handles closing the file, so you don’t need to manually close it. This helps avoid memory leaks and ensures system resources are freed up.

You can also specify the number of characters to read:

# Using 'with' statement to open the file 
with open('demo.txt', 'r') as file:
    # Reading the first 5 characters of the file
    content = file.read(5) 
    print(content)

Output:

Hello

(2) The readline() Method

The readline() method reads one line at a time from a file and returns it as a string. Each time it is called, it moves to the next line in the file. This method is well suited for large files, since it does not load the entire file into memory at once.

First let’s update the contents of demo.txt file to contain multiple lines:

Hello, from the
demo.txt file

Now let’s read the file line by line:

# Using 'with' statement to open the file 
with open('demo.txt', 'r') as file:
    # Reading the first two lines of the file one at a time
    line1 = file.readline()
    line2 = file.readline()
    print(line1)
    print(line2)

Output:

Hello, from the

demo.txt file

Note that each line includes a newline character (\n) at the end, which is why you extra spacing when printing lines directly.

(3) The readlines() Method

The readlines() method reads all lines from a file and returns them as a list of strings. Each element in the list represents one line from the file. This method is best suited for small to medium-sized files, since the entire file is loaded into memory.

For example:

# Using 'with' statement to open the file 
with open('demo.txt', 'r') as file:
    # Reading all lines from the file into a list
    lines = file.readlines()
    print(lines)

Output:

['Hello, from the\n', 'demo.txt file']

(4) Iterating Through a File

Iterating directly over a file object is the most memory-efficient way to read large files.

For example:

with open('demo.txt', 'r') as file:
    for line in file:
        print(line)

Output:

Hello, from the

demo.txt file

This approach read one line at a time without loading the entire file into memory, making it ideal for processing log files or large datasets.

Writing to Files in Python

Writing data to files allows your Python programs to save results, generate reports, or log activity. Python makes this process straightforward with write-enabled file modes.

(1) Writing with the write() Method

To write to a file, open the file in write ('w') or append ('a') mode.

with open("output.txt", "w") as file:
    file.write("This is the first line.\n")
    file.write("This is the second line.")

If output.txt file doesn’t exist, Python will create it. If it does exist, using 'w' will overwrite its content.

The output.text file should contain:

This is the first line.
This is the second line.

(2) Appending to a File

If you want to add content without removing existing data, use append mode ('a').

with open("output.txt", "a") as file:
    file.write("\nThis line was added later.")

Now output.text should contain:

This is the first line.
This is the second line.
This line was added later.

(3) Writing Multiple Lines with writelines()

The writelines() method writes a list of stings to a file.

lines = ["Line one\n", "Line two\n", "Line three\n"]

with open("output.txt", "w") as file:
    file.writelines(lines)

Now the output.txt file should contain:

Line one
Line two
Line three

Keep in mind that writelines() method doesn’t automatically add newline characters — you must include them yourself.

Opening Files From a Different Location

If your file is not in the same directory as your Python script, you must provide the correct file path when opening it.

Python supports two common types of paths:

Absolute Paths

An absolute path specifies the full location of the file on your system.

Windows

file = open("C:/Users/John/Documents/example.txt", "r")

macOS or Linux

file = open("/Users/john/Documents/example.txt", "r")

While absolute paths are straightforward, they are often system-specific and can make your code less portable.

Relative Paths

A relative path is based on the location of your Python script and is often peferred because it makes your project easier to move between systems.

Let’s say our project structure looks like this:

project_folder/
├── app.py
└── data/
    └── demo.txt

To open demo.txt from app.py:

file = open("data/demo.txt", "r")

Cross-Platform Path Handling in Python

To handle paths reliably across different operating system, Python provides two excellent built-in options:

Path Handling with os.path

# Traditional approach with os.path
import os

file_path = os.path.join("data", "demo.txt")

with open(file_path, "r") as file:
    content = file.read()
    print(content)

This method automatically uses the correct path separator for your operating system (\ on windows, and / on macOS and Linux).

Path Handling with pathlib (Recommended)

# Modern approach using pathlib (Python 3.4+)
from pathlib import Path

file_path = Path("data") / "demo.txt"

with open(file_path, "r") as file:
    content = file.read()
    print(content)

The pathlib module provides an object-oriented approach that is often more intuitive, especially when working with complex file systems.

Handling FileNotFoundError

Always assume that a file might not exist at the specified path. To prvent your program from crashing, catch the exception and handle it appropriately.

For example:

from pathlib import Path
file_path = Path("data") / "demo22.txt"

try:
    with open(file_path, "r") as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print(f"Error: The file {file_path} was not found.")

Output:

Error: The file data\demo22.txt was not found.

This makes your code more robust and avoids unexpected crashes when file are missing or paths are incorrect.