ZetCode

Python os.read Function

Last modified April 11, 2025

This comprehensive guide explores Python's os.read function, which performs low-level file reading using file descriptors. We'll cover file descriptors, buffer sizes, error handling, and practical examples.

Basic Definitions

The os.read function reads up to n bytes from a file descriptor. It's a low-level I/O operation that works directly with file descriptors.

Key parameters: fd (file descriptor), n (maximum bytes to read). Returns bytes read as bytes object. May raise OSError for invalid descriptors.

Reading a File with os.read

This basic example demonstrates how to open a file and read its contents using os.read. We first get a file descriptor with os.open.

basic_read.py
import os

# Open file and get file descriptor
fd = os.open("example.txt", os.O_RDONLY)

# Read up to 1024 bytes
data = os.read(fd, 1024)
print(f"Read {len(data)} bytes:")
print(data.decode('utf-8'))

# Close file descriptor
os.close(fd)

This example opens a file in read-only mode, reads up to 1024 bytes, then closes the descriptor. The data is returned as bytes and needs decoding.

Note that os.read may return fewer bytes than requested, even if more are available. This is normal behavior for low-level I/O operations.

Reading a File in Chunks

For large files, reading in chunks is more efficient. This example shows how to read a file piece by piece until EOF is reached.

chunked_read.py
import os

CHUNK_SIZE = 4096  # 4KB chunks
fd = os.open("large_file.bin", os.O_RDONLY)

total_bytes = 0
while True:
    chunk = os.read(fd, CHUNK_SIZE)
    if not chunk:  # EOF reached
        break
    total_bytes += len(chunk)
    # Process chunk here
    print(f"Read chunk of {len(chunk)} bytes")

os.close(fd)
print(f"Total bytes read: {total_bytes}")

The loop continues reading until os.read returns an empty bytes object, indicating EOF. Each chunk is processed as it's read.

This approach is memory-efficient as it doesn't load the entire file at once. The chunk size can be adjusted based on performance needs.

Reading from Standard Input

os.read can read from standard input (file descriptor 0). This example demonstrates reading user input directly from stdin.

stdin_read.py
import os
import sys

print("Type something and press Enter (Ctrl+D to end):")

# Read from stdin (fd 0)
try:
    while True:
        data = os.read(0, 1024)  # STDIN_FILENO is 0
        if not data:
            break
        print(f"You entered: {data.decode('utf-8').strip()}")
except KeyboardInterrupt:
    print("\nInterrupted by user")

This reads directly from standard input until EOF (Ctrl+D) or interrupt. The data is decoded from bytes to a string for display.

Note this is lower-level than input() and requires manual handling of encoding and newlines. It's useful for binary stdin reading.

Non-blocking File Reading

With non-blocking file descriptors, os.read can be used for asynchronous I/O. This example shows non-blocking read behavior.

nonblocking_read.py
import os
import errno

# Open file in non-blocking mode
fd = os.open("fifo_pipe", os.O_RDONLY | os.O_NONBLOCK)

try:
    while True:
        try:
            data = os.read(fd, 1024)
            if data:
                print(f"Data received: {data.decode()}")
            else:
                print("No data available")
                break
        except BlockingIOError:
            print("No data ready - would block")
            # In real code, you might wait here
            break
finally:
    os.close(fd)

When no data is available, non-blocking mode raises BlockingIOError instead of waiting. This is useful for event loops and async I/O.

The example assumes a named pipe (fifo) exists. Real code would need proper error handling and likely an event loop.

Reading Binary Data

os.read is ideal for reading binary files since it returns raw bytes. This example reads a binary file and processes its contents.

binary_read.py
import os

def read_binary_file(filename):
    fd = os.open(filename, os.O_RDONLY)
    try:
        # Read first 4 bytes (could be a magic number)
        header = os.read(fd, 4)
        print(f"File header: {header.hex()}")

        # Read rest of file
        remaining = b''
        while True:
            chunk = os.read(fd, 4096)
            if not chunk:
                break
            remaining += chunk

        return header + remaining
    finally:
        os.close(fd)

data = read_binary_file("image.png")
print(f"Total bytes read: {len(data)}")
print(f"First 16 bytes: {data[:16].hex()}")

This reads a binary file (PNG image), first extracting the header then the remaining contents. The hex representation shows binary data clearly.

Binary mode preserves all bytes exactly as they appear in the file, unlike text mode which may perform newline conversions.

Error Handling with os.read

Proper error handling is crucial when using low-level I/O. This example demonstrates comprehensive error handling for os.read.

error_handling.py
import os
import errno

def safe_read(fd, n):
    try:
        data = os.read(fd, n)
        if not data:
            print("Reached end of file")
            return None
        return data
    except OSError as e:
        if e.errno == errno.EBADF:
            print("Error: Bad file descriptor")
        elif e.errno == errno.EINTR:
            print("Error: Interrupted system call")
        elif e.errno == errno.EIO:
            print("Error: I/O error occurred")
        else:
            print(f"Unexpected error: {e}")
        return None

# Example usage
try:
    fd = os.open("example.txt", os.O_RDONLY)
    data = safe_read(fd, 1024)
    if data:
        print(data.decode('utf-8'))
finally:
    if 'fd' in locals():
        os.close(fd)

The safe_read function handles various error conditions that os.read might encounter. Each error type gets specific handling.

The finally block ensures the file descriptor is closed even if errors occur. This prevents resource leaks in error scenarios.

Performance Considerations

Best Practices

Source References

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Python tutorials.