python file io reading writing

File Input/Output in Python

Learning objectives

In this guide you will learn to:

  • open and close files safely with with;
  • read and write text files (.txt, .csv, etc.);
  • iterate over the lines of a file efficiently;
  • handle binary files (images, raw data);
  • move around inside a file with seek() and tell().

Introduction: Opening Files

To work with a file you must first open it with the open(filename, mode) function.

Opening Modes

The most important ones are:

  • 'r' (Read): Reading (default). Error if the file does not exist.
  • 'w' (Write): Writing. Overwrites the file if it exists, creates it otherwise.
  • 'a' (Append): Writing at the end. Adds data without deleting existing content.
  • 'b' (Binary): Combined with the above for binary files (e.g. 'rb', 'wb').

The with Context Manager

It is essential to always close files to release resources. In Python, the best way is to use the with block, which closes the file automatically even if an error occurs.

# DON'T DO THIS (risky if an error occurs before close)
f = open("data.txt", "r")
content = f.read()
f.close()

# DO THIS (safe and Pythonic)
with open("data.txt", "r") as f:
    content = f.read()
# The file is already closed here

Text Files

Reading

There are several methods for reading the content:

  1. read(): Reads the entire file as a single string.
  2. readline(): Reads one line at a time (including the trailing \n).
  3. readlines(): Reads all lines and returns a list of strings.
  4. Direct iteration: The most efficient method for large files.
# Best method for iterating over a file line by line
with open("list.txt", "r") as f:
    for line in f:
        # line includes the newline character
        print(line.strip())  # strip() removes leading/trailing whitespace and \n

Searching for specific lines with a for loop:

# The for loop is the standard way to read one line at a time.
# It does not load the entire file into memory!
with open("log.txt", "r") as f:
    for line in f:
        if line.startswith("ERROR:"):
            print("Error found:", line.strip())

Writing

with open("output.txt", "w") as f:
    f.write("First line\n")   # \n must be added explicitly
    f.write("Second line\n")

    # Writing a list of lines
    lines = ["Third\n", "Fourth\n"]
    f.writelines(lines)

Example: Counting lines

count = 0
with open("log.txt", "r") as f:
    for line in f:
        count += 1
print(f"The file has {count} lines.")

Binary Files

Binary files (images, audio, executables) are not divided into lines and do not use encodings like UTF-8. They are read and written as sequences of bytes.

# Copying an image (byte by byte)
with open("photo.jpg", "rb") as source:      # rb = read binary
    data = source.read()                     # Reads all bytes

with open("photo_copy.jpg", "wb") as dest:   # wb = write binary
    dest.write(data)

Reading in chunks with a while loop — useful for large files:

# For large files, read in "chunks" until the end
CHUNK_SIZE = 4096  # Read 4 KB at a time

with open("video.mp4", "rb") as f:
    while True:
        data = f.read(CHUNK_SIZE)
        if not data:  # Empty bytes means end of file
            break
        # Process the data (e.g. save it, send it, etc.)
        pass

Note: When reading in binary mode you get bytes objects (e.g. b'\x89PNG...'), not strings.

Moving around in the File: seek() and tell()

The file has a “cursor” indicating the current position (in bytes). When you read, the cursor advances.

  • tell(): Returns the current cursor position (integer).
  • seek(offset, whence): Moves the cursor.
    • offset: How many bytes to move.
    • whence: Where to start from (0: start of file, 1: current position, 2: end of file).

Note: In text files, seek() is only partially supported (usually only to the beginning seek(0) or to positions obtained from tell()). In binary files it is fully supported.

with open("data.bin", "rb") as f:
    print(f.read(10))   # Reads the first 10 bytes
    print(f.tell())     # Prints 10

    f.seek(0)           # Go back to the beginning
    print(f.read(5))    # Re-reads the first 5 bytes

    f.seek(0, 2)            # Go to the end of the file
    size = f.tell()         # Position at the end equals file size!
    print(f"The file is {size} bytes")

Practical Exercises

Exercise 1 — Log File Analysis

You have a text file server.log.

  1. Count how many lines contain the word “ERROR”.
  2. Create a new file errors_only.txt copying only those lines into it.

Exercise 2 — Hidden Message

You have a binary file. You know the secret message starts at byte 50 and ends at byte 100. Write a script that:

  1. Opens the file in binary mode.
  2. Moves to byte 50.
  3. Reads 50 bytes.
  4. Tries to decode them as text (data.decode('utf-8')) and prints the result.