FILE BUFFERING - Understanding and controlling file buffering
Python
#!/usr/bin/env python3
"""
FILE BUFFERING - Understanding and controlling file buffering
Demonstrates different buffering modes and their effects
"""
import os
import tempfile
import time
print("=" * 60)
print("FILE BUFFERING - Controlling I/O Performance")
print("=" * 60)
temp_dir = tempfile.gettempdir()
# Example 1: Default buffering
print("\n1. Default Buffering Behavior")
print("-" * 40)
default_file = os.path.join(temp_dir, "default.txt")
with open(default_file, 'w') as f:
print(f" Buffer size: {f.buffer.raw._CHUNK_SIZE if hasattr(f, 'buffer') else 'default'}")
f.write("Line 1\n")
print(" Wrote line 1 (buffered)")
f.write("Line 2\n")
print(" Wrote line 2 (buffered)")
# Data written to disk when file closes
print(" File closed, buffer flushed to disk")
# Example 2: Unbuffered writing (binary mode)
print("\n2. Unbuffered Writing (Binary Mode)")
print("-" * 40)
unbuffered_file = os.path.join(temp_dir, "unbuffered.txt")
# buffering=0 only works in binary mode
with open(unbuffered_file, 'wb', buffering=0) as f:
f.write(b"Line 1\n")
print(" Wrote line 1 (unbuffered, immediate disk write)")
f.write(b"Line 2\n")
print(" Wrote line 2 (unbuffered, immediate disk write)")
# Example 3: Line buffering (text mode)
print("\n3. Line Buffering (Text Mode)")
print("-" * 40)
line_buffered_file = os.path.join(temp_dir, "line_buffered.txt")
# buffering=1 means line buffering for text files
with open(line_buffered_file, 'w', buffering=1) as f:
f.write("First line\n")
print(" Wrote first line (flushed due to newline)")
f.write("Second")
print(" Wrote partial line (still in buffer)")
f.write(" line\n")
print(" Completed line (flushed)")
# Example 4: Custom buffer size
print("\n4. Custom Buffer Size")
print("-" * 40)
custom_buffer_file = os.path.join(temp_dir, "custom_buffer.txt")
buffer_size = 100 # 100 bytes
with open(custom_buffer_file, 'w', buffering=buffer_size) as f:
print(f" Using {buffer_size} byte buffer")
for i in range(20):
f.write(f"Line {i}\n")
print(" Wrote 20 lines (may still be in buffer)")
# Buffer flushed when full or file closes
# Example 5: Manual flushing
print("\n5. Manual Flush Control")
print("-" * 40)
flush_file = os.path.join(temp_dir, "flush.txt")
with open(flush_file, 'w') as f:
f.write("Before flush\n")
print(" Wrote data (in buffer)")
f.flush()
print(" Called flush() - data written to disk")
f.write("After flush\n")
print(" Wrote more data (in buffer again)")
# Example 6: Buffering performance comparison
print("\n6. Buffering Performance Comparison")
print("-" * 40)
# Buffered writing
buffered_file = os.path.join(temp_dir, "perf_buffered.txt")
start = time.time()
with open(buffered_file, 'w') as f:
for i in range(1000):
f.write(f"Line {i}\n")
buffered_time = time.time() - start
print(f" Buffered: {buffered_time:.4f} seconds")
# Unbuffered writing (binary)
unbuffered_file2 = os.path.join(temp_dir, "perf_unbuffered.txt")
start = time.time()
with open(unbuffered_file2, 'wb', buffering=0) as f:
for i in range(1000):
f.write(f"Line {i}\n".encode())
unbuffered_time = time.time() - start
print(f" Unbuffered: {unbuffered_time:.4f} seconds")
print(f" Speedup: {unbuffered_time / buffered_time:.2f}x faster with buffering")
# Example 7: Reading with different buffer sizes
print("\n7. Reading with Different Buffer Sizes")
print("-" * 40)
read_file = os.path.join(temp_dir, "read_test.txt")
# Create large file
with open(read_file, 'w') as f:
for i in range(100):
f.write(f"Line {i}: " + "x" * 50 + "\n")
# Read with small buffer
start = time.time()
with open(read_file, 'r', buffering=512) as f:
data = f.read()
small_buffer_time = time.time() - start
print(f" Small buffer (512): {small_buffer_time:.4f}s")
# Read with large buffer
start = time.time()
with open(read_file, 'r', buffering=8192) as f:
data = f.read()
large_buffer_time = time.time() - start
print(f" Large buffer (8192): {large_buffer_time:.4f}s")
# Example 8: Buffer and seek operations
print("\n8. Buffer Behavior with Seek")
print("-" * 40)
seek_file = os.path.join(temp_dir, "seek_test.txt")
with open(seek_file, 'w+') as f:
f.write("ABCDEFGHIJ")
print(" Wrote: ABCDEFGHIJ")
# Seek back
f.seek(0)
f.write("123")
print(" Seeked to start, wrote: 123")
# Flush to see result
f.flush()
# Read back
f.seek(0)
content = f.read()
print(f" Content: {content}")
# Example 9: Detecting buffer status
print("\n9. Checking Buffer Status")
print("-" * 40)
status_file = os.path.join(temp_dir, "status.txt")
with open(status_file, 'w') as f:
print(f" File writable: {f.writable()}")
print(f" File closed: {f.closed}")
f.write("Some data")
print(" Wrote data")
# Check if seekable (affects buffering)
print(f" File seekable: {f.seekable()}")
print(f" After context - closed: {f.closed}")
# Example 10: Binary vs text buffering
print("\n10. Binary vs Text Mode Buffering")
print("-" * 40)
# Text mode
text_file = os.path.join(temp_dir, "text_mode.txt")
with open(text_file, 'w', buffering=1) as f:
print(f" Text mode, line buffering")
f.write("Line 1\n")
f.write("Line 2\n")
# Binary mode
binary_file = os.path.join(temp_dir, "binary_mode.txt")
with open(binary_file, 'wb', buffering=1024) as f:
print(f" Binary mode, 1024 byte buffer")
f.write(b"Line 1\n")
f.write(b"Line 2\n")
# Example 11: Flushing on critical operations
print("\n11. Flushing for Critical Operations")
print("-" * 40)
log_file = os.path.join(temp_dir, "critical.log")
with open(log_file, 'w') as f:
f.write("Starting critical operation\n")
f.flush() # Ensure logged before proceeding
print(" Log entry flushed")
# Simulate critical operation
time.sleep(0.01)
f.write("Critical operation completed\n")
f.flush() # Ensure logged
print(" Completion logged and flushed")
# Cleanup
cleanup_files = [
default_file, unbuffered_file, line_buffered_file,
custom_buffer_file, flush_file, buffered_file,
unbuffered_file2, read_file, seek_file, status_file,
text_file, binary_file, log_file
]
for f in cleanup_files:
if os.path.exists(f):
os.remove(f)
print("\n" + "=" * 60)
print("Key Points:")
print(" - Default: buffering enabled for performance")
print(" - buffering=0: unbuffered (binary only)")
print(" - buffering=1: line buffering (text mode)")
print(" - buffering=N: custom buffer size")
print(" - flush() forces write to disk")
print(" - Buffering significantly improves performance")
print("=" * 60)