Working with Files in Python

Any variable lives only while the program is running: close it, and your to-do list, the score you racked up, your saved settings are gone. To make data survive a restart, you write it to a file on disk and read it back next time. That's what notes, game saves, report exports — almost any application — rest on.

A file is a named set of data on disk. Let's go through it in order: how to open a file, read from it, write to it, and why it matters to close it.

Basic File Operations

In Python, working with files usually includes the following steps:

  1. Opening a file — specify the file and the mode of working with it
  2. Reading or writing — perform the necessary operations with the file
  3. Closing the file — free up system resources

Let's consider each of these steps in more detail.

Opening Files

To open a file in Python, the open() function is used. It takes at least two parameters: the path to the file and the opening mode.

Here are the basic file opening modes:

ModeDescription
'r'Reading (default mode)
'w'Writing (creates a new file or overwrites an existing one)
'a'Appending — adds data to the end of the file
'b'Binary mode (e.g., 'rb' for reading a binary file)
't'Text mode (default mode)
'+'Updating (reading and writing)

Examples of opening files in different modes:

Python 3.13
# 'w' creates the file (or overwrites it) and opens it for writing
file = open('notes.txt', 'w')
file.write("Buy milk")
file.close()

# 'r' opens an existing file for reading
file = open('notes.txt', 'r')
print(file.read())
Buy milk
file.close()

Note: 'r' requires the file to already exist — otherwise you get a FileNotFoundError. 'w' is the opposite: if the file doesn't exist it creates it, and if it does, it wipes the old contents.

Reading from a File

After opening a file, its contents can be read in several ways. In the examples below the file is opened with with open(...) as ... — a safe way that closes the file for you at the end; we'll cover it shortly, for now just read it as "open the file for the duration of the block".

Reading the entire file

Python 3.13
# Let's create a test file
with open('sample.txt', 'w') as f:
    f.write("First line\nSecond line\nThird line")

# Reading the entire file at once
with open('sample.txt', 'r') as file:
    content = file.read()
    print("File contents:")
File contents:
    print(content)
First line
Second line
Third line

Reading a file line by line

Python 3.13
# Reading a file line by line using a loop
with open('sample.txt', 'r') as file:
    print("Reading line by line:")
Reading line by line:
    for line in file:
        print(f"  Line: {line.strip()}")
  Line: First line
  Line: Second line
  Line: Third line

Reading a specific number of characters

Python 3.13
# Reading a specific number of characters
with open('sample.txt', 'r') as file:
    first_10_chars = file.read(10)
    print(f"First 10 characters: {first_10_chars}")
First 10 characters: First line
    # Reading the next 10 characters
    next_10_chars = file.read(10)
    print(f"Next 10 characters: {next_10_chars}")
Next 10 characters:
Second li

Reading all lines into a list

Python 3.13
# Reading all lines into a list
with open('sample.txt', 'r') as file:
    lines = file.readlines()
    print(f"List of lines: {lines}")
List of lines: ['First line\n', 'Second line\n', 'Third line']

Writing to a File

Writing data to a file can also be done in different ways:

Writing a string

Python 3.13
# Writing a string to a file
with open('output.txt', 'w') as file:
    file.write("Hello, world!\n")
    file.write("Python is a great programming language.")

# Let's check what was written
with open('output.txt', 'r') as file:
    content = file.read()
    print("File contents after writing:")
File contents after writing:
    print(content)
Hello, world!
Python is a great programming language.

Writing multiple lines

Python 3.13
# Writing a list of strings to a file
lines = ["First line", "Second line", "Third line"]

with open('lines.txt', 'w') as file:
    for line in lines:
        file.write(line + '\n')

# Alternative way: using writelines()
with open('lines2.txt', 'w') as file:
    # Don't forget to add newline characters
    file.writelines([line + '\n' for line in lines])

# Let's check the second file
with open('lines2.txt', 'r') as file:
    content = file.read()
    print("Contents of lines2.txt:")
Contents of lines2.txt:
    print(content)
First line
Second line
Third line

Appending data to the end of a file

Python 3.13
# Appending data to the end of a file (mode 'a')
with open('output.txt', 'a') as file:
    file.write("\nThis line was added later.")

# Let's check the result
with open('output.txt', 'r') as file:
    content = file.read()
    print("File contents after appending:")
File contents after appending:
    print(content)
Hello, world!
Python is a great programming language.
This line was added later.

The with Context Manager

In all the examples above the file was opened with with open(...) as file:. Now it's time to explain this construct.

An open file has to be closed: while it's open it holds system resources, and written data may not reach the disk until it's closed. You can close it manually:

Python 3.13
file = open('example.txt', 'w')
file.write("Example text")
file.close()

The catch is that it's easy to forget close(). And if something goes wrong between opening and closing and the program is interrupted, close() is never reached, and the file stays open.

The with construct takes this off your hands: it closes the file when the block ends, no matter the outcome.

Python 3.13
with open('example.txt', 'w') as file:
    file.write("Example text")
# the file is already closed here automatically
print("File automatically closed after the with block")
File automatically closed after the with block

Exception Handling When Working with Files

Various errors can occur when working with files:

  • The file doesn't exist
  • Insufficient permissions to access the file
  • The disk is full
  • Etc.

Catching such errors and reacting to them is the job of the try/except construct — it has its own lesson later in the course. Here it's enough to see it in action on files: the try block attempts the operation, and except catches a specific error if it happened.

Python 3.13
# Handling possible errors when opening a file
try:
    with open('non_existent_file.txt', 'r') as file:
        content = file.read()
except FileNotFoundError:
    print("Error: File not found!")
except PermissionError:
    print("Error: Insufficient permissions to access the file!")
except Exception as e:
    print(f"An error occurred: {e}")
Error: File not found!

Additional File Operations

Python provides many additional capabilities for working with files:

Moving the Pointer

Python 3.13
# A small file for the example
with open('demo.txt', 'w') as file:
    file.write("Hello, world!")

# seek() moves the pointer to a given position
with open('demo.txt', 'r') as file:
    print(file.read(5))                      # first 5 characters
Hello
    file.seek(0)                             # back to the start
    print("After seek(0):", file.read(5))
After seek(0): Hello
    file.seek(7)                             # jump to position 7
    print("After seek(7):", file.read(5))
After seek(7): world

Here the text is English, so the position matches the character number. A subtlety: seek and tell actually count the position in bytes. For Latin letters one character is one byte, but a character outside ASCII — a Cyrillic letter in UTF-8, say — takes two bytes, so for such text the position numbers shift.

Getting the Current Position

Python 3.13
# tell() returns the current pointer position
with open('demo.txt', 'r') as file:
    print(f"Initial position: {file.tell()}")
Initial position: 0
    file.read(5)
    print(f"After reading 5 characters: {file.tell()}")
After reading 5 characters: 5

Working with File Paths

When working with files, it's important to specify paths correctly. Python provides the os.path module and the pathlib module to make working with paths easier:

In the sandbox the current directory is /home/pyodide; on your own computer the path will differ.

Python 3.13
import os

# Current working directory
current_dir = os.getcwd()
print(f"Current directory: {current_dir}")
Current directory: /home/pyodide
# Joining paths (correctly handling separators)
data_file = os.path.join(current_dir, 'data', 'info.txt')
print(f"Path to file: {data_file}")
Path to file: /home/pyodide/data/info.txt
# Checking if a file exists
sample_exists = os.path.exists('sample.txt')
print(f"File sample.txt exists: {sample_exists}")
File sample.txt exists: True
# Getting the filename and extension
filename = "path/to/document.pdf"
basename = os.path.basename(filename)
name, ext = os.path.splitext(basename)
print(f"Filename: {name}, extension: {ext}")
Filename: document, extension: .pdf

A more modern approach using pathlib:

Python 3.13
from pathlib import Path

# Current directory
current_path = Path.cwd()
print(f"Current directory: {current_path}")
Current directory: /home/pyodide
# Creating a path
data_file = current_path / 'data' / 'info.txt'
print(f"Path to file: {data_file}")
Path to file: /home/pyodide/data/info.txt
# Checking if a file exists
sample_path = Path('sample.txt')
print(f"File sample.txt exists: {sample_path.exists()}")
File sample.txt exists: True
# Getting the filename and extension
document_path = Path("path/to/document.pdf")
print(f"Filename: {document_path.stem}, extension: {document_path.suffix}")
Filename: document, extension: .pdf

Understanding Check

Which code correctly opens a file for writing and appends a string to the end of the file?

In future lessons, we'll delve deeper into working with specific file types, such as text files, CSV, JSON, and others.