ZetCode

Python sqlite3.Blob.tell 方法

上次修改时间:2025 年 4 月 15 日

本综合指南探讨了 Python 的 sqlite3.Blob.tell 方法,该方法报告 blob 文件指针的当前位置。我们将涵盖基本用法、实际示例和常用模式。

基本定义

sqlite3.Blob 类表示 SQLite 中的二进制大对象 (BLOB)。它提供对存储在数据库表中的 BLOB 数据的类文件访问。

tell 方法返回 blob 文件指针的当前位置。此位置指示下一次读取或写入操作将在 blob 数据中的何处发生。

Blob tell 基本用法

此示例演示了 tell 方法与 blob 对象的基本用法。 我们创建一个带有 blob 列的表并检查指针位置。

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()

该示例表明,tell 从 0(blob 的开头)开始,并在我们读取数据时递增。该位置是从 blob 开头开始的字节数。

请始终记住在完成后关闭 blob 对象以释放资源。 with 语句确保数据库连接的正确清理。

写入 Blob 后使用 Tell

此示例演示了写入 blob 时 tell 的行为。我们将创建一个 blob,写入数据并跟踪位置。

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()

每个写入操作都会将位置推进写入的字节数。 zeroblob 函数创建一个指定大小的 blob,并用零填充。

当您需要跟踪已写入多少数据或在 blob 数据中实现随机访问模式时,此模式很有用。

Seek 和 Tell 操作

此示例将 seektell 结合使用,以演示如何在 blob 中导航并跟踪位置变化。

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()

该示例显示了 tell 如何准确地反映来自绝对和相对 seek 的位置变化。 seek 的第二个参数控制参考点(0=开始,1=当前,2=结束)。

此技术对于实现复杂的 blob 访问模式至关重要,在这种模式下,您需要跳转到二进制数据中的特定位置。

Tell 与大型 Blob

此示例演示了 tell 在大型 blob 中的行为,表明它始终如一地工作,而与 blob 大小无关。

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()

该示例以 1MB 的块处理 5MB 的 blob,显示了即使使用大型数据,tell 如何跟踪确切的位置。无论 blob 大小如何,位置始终准确。

对于非常大的 blob,像这样分块读取比一次读取整个 blob 更节省内存。 tell 帮助监控进度。

Tell 与空 Blob

此示例显示了 tell 在空 blob 和零长度读取/写入中的行为。

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()

对于空 blob,tell 从 0 开始。尝试从空 blob 读取不会改变位置。写入数据会按预期推进位置。

在处理数据库架构中可能为空的可选 blob 字段时,了解此行为非常重要。

Tell 与只读模式下的 Blob

此示例演示了以只读模式打开 blob 时 tell 的行为。

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()

在只读模式下,tell 对于读取操作正常工作,但禁止写入。位置仅因读取操作而改变。

当您需要确保 blob 数据不会被意外修改,同时仍然需要读取和跟踪数据中的位置时,这非常有用。

Tell 与多个 Blob 操作

最后一个示例在更复杂的场景中显示了 tell,其中包含多个操作和位置检查。

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()

该示例显示了同时跟踪多个 blob 中的位置。每个 blob 维护其自身的独立位置,tell 会准确地报告该位置。

当处理结构化二进制数据时,此模式很有用,其中不同的部分存储在单独的 blob 列中,但需要一起处理。

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直撰写编程文章。 迄今为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程