ZetCode

Python sqlite3.Blob.tell Method

Last modified April 15, 2025

This comprehensive guide explores Python's sqlite3.Blob.tell method, which reports the current position of the blob's file pointer. We'll cover basic usage, practical examples, and common patterns.

Basic Definitions

The sqlite3.Blob class represents a Binary Large Object (BLOB) in SQLite. It provides file-like access to BLOB data stored in database tables.

The tell method returns the current position of the blob's file pointer. This position indicates where the next read or write operation will occur within the blob data.

Basic Blob tell Usage

This example demonstrates the basic usage of tell with a blob object. We create a table with a blob column and examine the pointer position.

basic_tell.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    conn.execute('CREATE TABLE images (id INTEGER PRIMARY KEY, data BLOB)')
    
    # Insert sample blob data
    blob_data = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    conn.execute('INSERT INTO images (data) VALUES (?)', (blob_data,))
    
    # Open blob and check position
    blob = conn.blobopen('images', 'data', 1, 'main')
    print(f"Initial position: {blob.tell()}")  # Output: 0
    
    # Read some data and check new position
    data = blob.read(5)
    print(f"After reading 5 bytes: {blob.tell()}")  # Output: 5
    
    blob.close()

The example shows that tell starts at 0 (beginning of blob) and increments as we read data. The position is in bytes from the start of the blob.

Always remember to close blob objects when done to free resources. The with statement ensures proper cleanup of database connections.

Tell After Writing to Blob

This example shows how tell behaves when writing to a blob. We'll create a blob, write data, and track the position.

write_tell.py
import sqlite3

with sqlite3.connect('blobs.db') as conn:
    conn.execute('CREATE TABLE IF NOT EXISTS documents (id INTEGER PRIMARY KEY, content BLOB)')
    conn.execute('INSERT INTO documents (content) VALUES (zeroblob(100))')
    
    # Open blob for writing
    blob = conn.blobopen('documents', 'content', 1, 'main')
    print(f"Start position: {blob.tell()}")  # 0
    
    # Write data and check position
    blob.write(b'Python ')
    print(f"After write: {blob.tell()}")  # 7
    
    blob.write(b'sqlite3.Blob')
    print(f"After second write: {blob.tell()}")  # 19
    
    blob.close()

Each write operation advances the position by the number of bytes written. The zeroblob function creates a blob of specified size filled with zeros.

This pattern is useful when you need to track how much data has been written or to implement random access patterns in blob data.

Seek and Tell Operations

This example combines seek with tell to demonstrate how to navigate within a blob and track position changes.

seek_tell.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    conn.execute('CREATE TABLE binaries (id INTEGER PRIMARY KEY, code BLOB)')
    conn.execute('INSERT INTO binaries (code) VALUES (?)', (b'X' * 1000,))
    
    blob = conn.blobopen('binaries', 'code', 1, 'main')
    print(f"Initial position: {blob.tell()}")  # 0
    
    # Jump to position 500
    blob.seek(500)
    print(f"After seek(500): {blob.tell()}")  # 500
    
    # Read 100 bytes
    data = blob.read(100)
    print(f"After read(100): {blob.tell()}")  # 600
    
    # Seek from current position
    blob.seek(-50, 1)  # Move back 50 bytes from current position
    print(f"After relative seek: {blob.tell()}")  # 550
    
    blob.close()

The example shows how tell accurately reflects position changes from both absolute and relative seeks. The second parameter to seek controls the reference point (0=start, 1=current, 2=end).

This technique is essential for implementing complex blob access patterns where you need to jump to specific positions within the binary data.

Tell with Large Blobs

This example demonstrates tell behavior with large blobs, showing it works consistently regardless of blob size.

large_blob.py
import sqlite3
import random

# Generate 5MB of random data
large_data = bytes(random.getrandbits(8) for _ in range(5 * 1024 * 1024))

with sqlite3.connect('large_data.db') as conn:
    conn.execute('CREATE TABLE IF NOT EXISTS big_files (id INTEGER PRIMARY KEY, payload BLOB)')
    conn.execute('INSERT INTO big_files (payload) VALUES (?)', (large_data,))
    
    blob = conn.blobopen('big_files', 'payload', 1, 'main')
    chunk_size = 1024 * 1024  # 1MB chunks
    total_read = 0
    
    while True:
        data = blob.read(chunk_size)
        if not data:
            break
        total_read += len(data)
        print(f"Current position: {blob.tell()}, Total read: {total_read}")
    
    blob.close()

The example processes a 5MB blob in 1MB chunks, showing how tell tracks the exact position even with large data. The position is always accurate regardless of blob size.

For very large blobs, reading in chunks like this is more memory-efficient than reading the entire blob at once. tell helps monitor progress.

Tell with Empty Blobs

This example shows tell behavior with empty blobs and zero-length reads/writes.

empty_blob.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    conn.execute('CREATE TABLE empty_blobs (id INTEGER PRIMARY KEY, empty BLOB)')
    conn.execute('INSERT INTO empty_blobs (empty) VALUES (?)', (b'',))
    
    blob = conn.blobopen('empty_blobs', 'empty', 1, 'main')
    print(f"Initial position: {blob.tell()}")  # 0
    
    # Attempt to read from empty blob
    data = blob.read(10)
    print(f"After read attempt: {blob.tell()}")  # 0
    
    # Write to empty blob
    blob.write(b'data')
    print(f"After write: {blob.tell()}")  # 4
    
    blob.close()

With empty blobs, tell starts at 0. Attempting to read from an empty blob doesn't change the position. Writing data advances the position as expected.

This behavior is important to understand when handling optional blob fields that might be empty in your database schema.

Tell with Blob in Readonly Mode

This example demonstrates tell behavior when the blob is opened in readonly mode.

readonly_tell.py
import sqlite3

with sqlite3.connect('readonly.db') as conn:
    conn.execute('CREATE TABLE IF NOT EXISTS logs (id INTEGER PRIMARY KEY, entries BLOB)')
    conn.execute('INSERT INTO logs (entries) VALUES (?)', (b'log entry 1\nlog entry 2',))
    
    # Open blob in readonly mode (set readable=False)
    blob = conn.blobopen('logs', 'entries', 1, 'main', readable=True, writable=False)
    print(f"Initial position: {blob.tell()}")  # 0
    
    # Read first line
    first_line = blob.read(11)
    print(f"After reading first line: {blob.tell()}")  # 11
    
    # Attempting to write would raise sqlite3.OperationalError
    try:
        blob.write(b'new data')
    except sqlite3.OperationalError as e:
        print(f"Write failed: {e}")
    
    blob.close()

In readonly mode, tell works normally for read operations but writing is prohibited. The position only changes from read operations.

This is useful when you need to ensure blob data isn't accidentally modified while still needing to read and track position within the data.

Tell with Multiple Blob Operations

This final example shows tell in a more complex scenario with multiple operations and position checks.

complex_tell.py
import sqlite3

with sqlite3.connect('complex.db') as conn:
    conn.execute('''CREATE TABLE IF NOT EXISTS records (
                     id INTEGER PRIMARY KEY,
                     header BLOB,
                     payload BLOB)''')
    
    # Insert record with header and payload
    conn.execute('INSERT INTO records (header, payload) VALUES (?, ?)',
                 (b'HEADER', b'PAYLOAD' * 100))
    
    # Open both blobs
    header_blob = conn.blobopen('records', 'header', 1, 'main')
    payload_blob = conn.blobopen('records', 'payload', 1, 'main')
    
    # Process header
    print(f"Header start: {header_blob.tell()}")
    header = header_blob.read()
    print(f"Header after read: {header_blob.tell()}")
    
    # Process payload in chunks
    chunk_size = 50
    while True:
        pos = payload_blob.tell()
        chunk = payload_blob.read(chunk_size)
        if not chunk:
            break
        print(f"Read {len(chunk)} bytes at position {pos}")
    
    header_blob.close()
    payload_blob.close()

The example shows tracking positions in multiple blobs simultaneously. Each blob maintains its own independent position that tell reports accurately.

This pattern is useful when working with structured binary data where different parts are stored in separate blob columns but need to be processed together.

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.