Resizing and Truncating Files in Python: Managing Capacity with truncate()

The file.truncate([size]) method resizes an open file stream to a specified byte length, discarding trailing bytes to reclaim disk storage or extending the file with zero bytes.

Required Access Mode: Truncating requires write permissions. Opening in read-only mode ('r') raises an io.UnsupportedOperation exception. For in-place resizing without erasing existing content on open, always use mode='r+' or mode='r+b'.

1. Method Syntax & Signature 🔝

The standard CPython signature for file.truncate() is:

file_object.truncate(size=None)
Parameter Type Default Behavior & Description
size int | None None Target size of the file in bytes. If omitted or None, the file is truncated to the current file pointer position as reported by tell().
Return Value int — Returns the new file size in bytes.
Exceptions io.UnsupportedOperation — Raised when attempting to truncate a stream opened in read-only mode (e.g. 'r' or 'rb').

2. Required File Access Modes: Why 'r+' is Optimal 🔝

Choosing the correct mode when invoking truncate() is critical to prevent unintended data destruction:

File Mode Truncate Supported? Open Behavior Recommended Role for truncate()
'r+' Yes Preserves file; positions at 0 Gold Standard: Inspect, seek, and resize in-place without erasing contents.
'r' No (raises error) Read-only Cannot truncate. Raises io.UnsupportedOperation: File not open for writing.
'a' / 'a+' Yes Preserves file; pointer at EOF Useful for truncating to an explicit byte limit (e.g. f.truncate(100)).
'w' / 'w+' Yes (Redundant) Erases file immediately to 0 bytes File is already empty upon opening, rendering truncate() largely redundant.

3. Explicit Size vs. Implicit Pointer Truncation 🔝

Python offers two distinct execution mechanics for resizing files:

Demonstration: Explicit Bytes vs. Current Position
# Pattern 1: Explicit byte limit
with open("archive.log", "r+", encoding="utf-8") as f:
    # Truncate to exactly 100 bytes regardless of cursor position
    new_size = f.truncate(100)
    print("File resized to:", new_size)

# Pattern 2: Implicit truncation at current cursor position (f.tell())
with open("records.txt", "r+", encoding="utf-8") as f:
    f.readline()  # Consume header row
    f.readline()  # Consume row 1
    # Truncate everything after the first two lines
    f.truncate()
    print("File truncated cleanly at current cursor offset:", f.tell())

4. Shrinking Files vs. Extending Files 🔝

When you pass a target size parameter, Python supports both down-sizing and up-sizing:

  • Shrinking (size < current_size): Bytes past the new boundary are removed, and filesystem blocks are marked for deallocation.
  • Extending (size > current_size): The file grows to the larger size. The newly allocated sparse space between the old end-of-file and the new boundary reads as null bytes (\x00 or 0x00).
Extending Files with Sparse Zero Padding
with open("sparse.bin", "r+b") as bin_stream:
    # Extend file to 1024 bytes; padding filled with \x00 bytes
    bin_stream.truncate(1024)
    print("File expanded to 1 KB with zero-byte padding.")

5. Cursor State After Truncation 🔝

A crucial technical detail is that truncate() does not alter the current file pointer offset. If your stream cursor was at byte 50 and you call f.truncate(20), the file pointer remains at byte 50 — now beyond the new EOF!

with open("data.txt", "r+", encoding="utf-8") as f:
    f.seek(50)
    f.truncate(20)
    
    # Notice: tell() is still at 50, past the new end of file
    print("Cursor offset:", f.tell())  # 50
    
    # Always seek back to a valid range before performing further I/O
    f.seek(0)

6. Real-World Engineering Recipes 🔝

Recipe 1: Clearing File Contents In-Place (truncate(0))

Reset an existing file to zero bytes without deleting the file or losing open OS file descriptors:

def clear_file_contents(filepath: str) -> None:
    with open(filepath, "r+", encoding="utf-8") as stream:
        stream.seek(0)
        stream.truncate(0)

clear_file_contents("temp_buffer.txt")
print("File cleared to 0 bytes safely in-place.")

Recipe 2: Capping Log File Size (Log Rolling Cap)

Cap oversized logs to a maximum byte threshold to prevent local disk exhaustion:

import os

def cap_log_file_size(log_path: str, max_bytes: int = 1048576) -> None:
    if os.path.exists(log_path) and os.path.getsize(log_path) > max_bytes:
        with open(log_path, "r+b") as f:
            f.truncate(max_bytes)

cap_log_file_size("debug.log", 50000)
print("Oversized log capped within quota bounds.")

7. Common Pitfalls & Boundary Traps 🔝

Trap 1: UnsupportedOperation in Read-Only Mode ('r')

Attempting to call truncate() in read mode ('r') raises io.UnsupportedOperation: File not open for writing. Always use 'r+' or 'r+b'.

Trap 2: Truncating in Append Mode Without an Explicit Argument

In append mode ('a'), the stream pointer sits at EOF by default. Calling bare f.truncate() without a size argument truncates at EOF — effectively doing nothing. Pass an explicit integer size (e.g. f.truncate(100)) if truncating in append mode.

8. Production Test Suite & Self-Checking Assertions 🔝

Run this complete test harness verifying file shrinking, pointer truncation, and zero-byte clearing:

TruncateVerifier Test Harness
import tempfile
import os

class TruncateVerifier:
    @staticmethod
    def shrink(path: str, size: int) -> int:
        with open(path, "r+b") as stream:
            stream.truncate(size)
        return os.path.getsize(path)

# Verification unit tests
with tempfile.TemporaryDirectory() as td:
    v = TruncateVerifier()
    test_file = os.path.join(td, "verify.bin")
    initial_bytes = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"  # 36 bytes
    with open(test_file, "wb") as f:
        f.write(initial_bytes)
        
    # Test 1: Shrink to exactly 10 bytes
    assert v.shrink(test_file, 10) == 10
    with open(test_file, "rb") as f:
        assert f.read() == b"0123456789"
        
    # Test 2: Truncate at current seek position (implicit size)
    with open(test_file, "r+b") as f:
        f.seek(4)
        f.truncate()
    assert os.path.getsize(test_file) == 4
    
    # Test 3: Clear file completely
    with open(test_file, "r+b") as f:
        f.truncate(0)
    assert os.path.getsize(test_file) == 0

print("All file.truncate() unit assertions passed successfully!")

Practice in Google Colab & GitHub 🔝

Open in Google Colab View on GitHub

Run all file truncate exercises interactively, test 'r+' in-place resizing, experiment with sparse file extension padding, and clear files in Google Colab.




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer