The io module provides Python's core I/O infrastructure. Most useful: StringIO and BytesIO for in-memory file-like objects.
StringIO: In-Memory Text Files
from io import StringIO
# Create in-memory text file
buffer = StringIO()
buffer.write("Hello, ")
buffer.write("World!")
# Get contents
contents = buffer.getvalue()
print(contents) # "Hello, World!"
# Read like a file
buffer.seek(0)
print(buffer.read()) # "Hello, World!"BytesIO: In-Memory Binary Files
from io import BytesIO
# Create in-memory binary file
buffer = BytesIO()
buffer.write(b"Binary data")
buffer.write(b"\x00\x01\x02")
# Get bytes
data = buffer.getvalue()
print(data) # b'Binary data\x00\x01\x02'
# Read
buffer.seek(0)
print(buffer.read(6)) # b'Binary'Initialize with Content
from io import StringIO, BytesIO
# Pre-populated StringIO
text_buffer = StringIO("Initial content")
print(text_buffer.read()) # "Initial content"
# Pre-populated BytesIO
binary_buffer = BytesIO(b"Initial bytes")
print(binary_buffer.read()) # b"Initial bytes"File-Like Interface
Both support standard file operations:
from io import StringIO
buffer = StringIO("Line 1\nLine 2\nLine 3\n")
# Read all
buffer.read()
# Read line
buffer.seek(0)
buffer.readline() # "Line 1\n"
# Iterate lines
buffer.seek(0)
for line in buffer:
print(line, end='')
# Position
buffer.seek(0) # Go to start
buffer.tell() # Current position
buffer.seek(0, 2) # Go to end
# Truncate
buffer.truncate(10)Practical Examples
Capture stdout
from io import StringIO
import sys
# Capture print output
old_stdout = sys.stdout
sys.stdout = buffer = StringIO()
print("This goes to buffer")
print("So does this")
sys.stdout = old_stdout
captured = buffer.getvalue()
print(f"Captured: {captured}")Test File Operations
from io import StringIO
import csv
def parse_csv(file_obj):
reader = csv.reader(file_obj)
return list(reader)
# Test without actual file
csv_data = StringIO("a,b,c\n1,2,3\n4,5,6")
result = parse_csv(csv_data)
assert result == [['a', 'b', 'c'], ['1', '2', '3'], ['4', '5', '6']]Generate Binary Content
from io import BytesIO
from PIL import Image
# Create image in memory
img = Image.new('RGB', (100, 100), color='red')
buffer = BytesIO()
img.save(buffer, format='PNG')
# Get bytes for upload, storage, etc.
image_bytes = buffer.getvalue()Stream Processing
from io import BytesIO
import gzip
# Compress data in memory
data = b"Compress this data" * 100
buffer = BytesIO()
with gzip.GzipFile(fileobj=buffer, mode='wb') as f:
f.write(data)
compressed = buffer.getvalue()
print(f"Original: {len(data)}, Compressed: {len(compressed)}")API Response Handling
from io import BytesIO
import requests
def download_to_buffer(url):
response = requests.get(url, stream=True)
buffer = BytesIO()
for chunk in response.iter_content(chunk_size=8192):
buffer.write(chunk)
buffer.seek(0)
return buffer
# Process without saving to disk
buffer = download_to_buffer("https://example.com/file.zip")Context Manager Support
from io import StringIO
# Auto-closes (though not strictly necessary for memory buffers)
with StringIO() as buffer:
buffer.write("content")
content = buffer.getvalue()The I/O Hierarchy
from io import IOBase, RawIOBase, BufferedIOBase, TextIOBase
# IOBase: Abstract base for all I/O
# RawIOBase: Raw binary I/O
# BufferedIOBase: Buffered binary I/O
# TextIOBase: Text I/O
# Check what type a file is
with open('file.txt', 'r') as f:
print(isinstance(f, TextIOBase)) # True
with open('file.bin', 'rb') as f:
print(isinstance(f, BufferedIOBase)) # TrueStringIO vs Regular Strings
from io import StringIO
# String: immutable, no file interface
text = "Hello"
# text.write("more") # Error
# StringIO: mutable, file interface
buffer = StringIO("Hello")
buffer.write("more") # Works
buffer.seek(0, 2) # Seek to end
buffer.write(" text")Performance Note
from io import StringIO
# Building strings: StringIO is efficient
buffer = StringIO()
for i in range(10000):
buffer.write(f"Line {i}\n")
result = buffer.getvalue()
# Equivalent but often slower:
result = ""
for i in range(10000):
result += f"Line {i}\n"
# Best for joining: use join
lines = [f"Line {i}\n" for i in range(10000)]
result = "".join(lines)Quick Reference
from io import StringIO, BytesIO
# StringIO: text
buf = StringIO()
buf = StringIO("initial")
buf.write("text")
buf.getvalue() # Get all content
buf.read() # Read from position
buf.readline() # Read one line
buf.seek(0) # Reset position
buf.tell() # Current position
buf.truncate() # Truncate at position
# BytesIO: binary
buf = BytesIO()
buf = BytesIO(b"initial")
buf.write(b"bytes")
buf.getvalue() # Get all bytes
buf.read() # Read from position| Class | Content | Use Case |
|---|---|---|
StringIO | Text (str) | Text processing, testing |
BytesIO | Binary (bytes) | Binary data, images, compression |
StringIO and BytesIO let you work with in-memory data using the file interface. Essential for testing and avoiding temporary files.
React to this post: