ZetCode

Python sqlite3.Blob.__len__ 方法

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

本综合指南探讨了 Python 的 sqlite3.Blob.__len__ 方法,该方法返回 BLOB(二进制大对象)的长度(以字节为单位)。我们将介绍基本用法、实际示例和最佳实践。

基本定义

BLOB 是 SQLite 中用于存储二进制数据的数据类型。sqlite3.Blob 类提供对 Python 中 BLOB 数据的访问。__len__ 方法返回 BLOB 的大小(以字节为单位)。

主要特性:当在 Blob 对象上使用 len 时调用,返回一个整数,并且仅适用于打开的 Blob 对象。该方法提供有效的尺寸检查,而无需将整个 BLOB 加载到内存中。

基本 BLOB 长度检查

此示例演示了创建具有 BLOB 列的表并使用 __len__ 方法检查其长度。

basic_blob_length.py
import sqlite3

with sqlite3.connect('blobs.db') as conn:
    conn.execute("CREATE TABLE IF NOT EXISTS images (id INTEGER PRIMARY KEY, data BLOB)")
    
    # Insert sample binary data
    binary_data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00'
    conn.execute("INSERT INTO images (data) VALUES (?)", (binary_data,))
    
    # Open BLOB and check length
    blob = conn.blobopen('images', 'data', 1, 'main')
    print(f"BLOB length: {len(blob)} bytes")  # Calls __len__
    blob.close()

此示例创建一个表,插入二进制数据,然后打开 BLOB 以检查其长度。len 函数在内部调用 __len__

请注意,我们在使用后正确关闭 BLOB 对象。长度与我们插入的二进制字符串的大小匹配(在本例中为 24 字节)。

检查空 BLOB 长度

此示例显示了 __len__ 对空 BLOB 的行为方式。

empty_blob.py
import sqlite3

with sqlite3.connect('empty_blobs.db') as conn:
    conn.execute("CREATE TABLE IF NOT EXISTS empty_blobs (id INTEGER PRIMARY KEY, empty_data BLOB)")
    
    # Insert empty BLOB
    conn.execute("INSERT INTO empty_blobs (empty_data) VALUES (?)", (b'',))
    
    # Check length of empty BLOB
    with conn.blobopen('empty_blobs', 'empty_data', 1, 'main') as blob:
        print(f"Empty BLOB length: {len(blob)} bytes")  # Returns 0

在这里,我们插入一个空字节对象并验证 __len__ 返回 0。该示例使用上下文管理器自动关闭 BLOB。

空 BLOB 在 SQLite 中是有效的,可用作占位符或默认值。__len__ 方法正确报告了它们的零大小。

比较 BLOB 长度

此示例演示了比较表中多个 BLOB 的长度。

compare_blobs.py
import sqlite3

with sqlite3.connect('compare_blobs.db') as conn:
    conn.execute("CREATE TABLE IF NOT EXISTS files (id INTEGER PRIMARY KEY, content BLOB)")
    
    # Insert files of different sizes
    small_file = b'small'
    medium_file = b'medium size content'
    large_file = b'large' * 1000
    
    conn.executemany("INSERT INTO files (content) VALUES (?)",
                    [(small_file,), (medium_file,), (large_file,)])
    
    # Compare lengths
    cursor = conn.cursor()
    cursor.execute("SELECT rowid FROM files ORDER BY rowid")
    for rowid, in cursor:
        with conn.blobopen('files', 'content', rowid, 'main') as blob:
            print(f"File {rowid} size: {len(blob)} bytes")

此代码插入三个不同大小的 BLOB,然后检索每个 BLOB 以比较它们的长度。__len__ 方法提供每个 BLOB 的大小。

该示例演示了如何有效地处理多个 BLOB,使用它们的长度进行比较或分析,而无需加载实际内容。

事务中的 BLOB 长度

此示例演示了在事务中检查 BLOB 长度。

transaction_blob.py
import sqlite3

with sqlite3.connect('transaction.db') as conn:
    conn.execute("CREATE TABLE IF NOT EXISTS documents (id INTEGER PRIMARY KEY, doc BLOB)")
    
    # Start transaction
    with conn:
        # Insert document
        doc_content = b'This is a document' * 100
        conn.execute("INSERT INTO documents (doc) VALUES (?)", (doc_content,))
        
        # Get last inserted rowid
        rowid = conn.execute("SELECT last_insert_rowid()").fetchone()[0]
        
        # Check length within transaction
        with conn.blobopen('documents', 'doc', rowid, 'main') as blob:
            print(f"Document size before commit: {len(blob)} bytes")
    
    # Verify length after commit
    with conn.blobopen('documents', 'doc', rowid, 'main') as blob:
        print(f"Document size after commit: {len(blob)} bytes")

此示例表明 __len__ 在事务内外均可工作。在提交之前和之后,BLOB 长度保持一致。

上下文管理器确保正确的事务处理,同时我们在操作的不同点检查 BLOB 大小。

BLOB 长度的错误处理

此示例演示了使用 __len__ 时的错误情况。

error_handling.py
import sqlite3

try:
    with sqlite3.connect('errors.db') as conn:
        conn.execute("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, data BLOB)")
        
        # Try to get length of closed BLOB
        blob = conn.blobopen('test', 'data', 1, 'main')
        blob.close()
        try:
            print(len(blob))  # Will raise Error
        except sqlite3.ProgrammingError as e:
            print(f"Error: {e}")
        
        # Try to get length of non-existent BLOB
        try:
            with conn.blobopen('test', 'data', 999, 'main') as blob:
                print(len(blob))
        except sqlite3.OperationalError as e:
            print(f"Error: {e}")
            
except sqlite3.Error as e:
    print(f"Database error: {e}")

此示例显示了两种常见的错误情况:在关闭的 BLOB 上调用 __len__ 和尝试打开不存在的 BLOB。两者都会引发适当的异常。

在处理 BLOB 时,适当的错误处理至关重要,因为由于各种原因(如连接关闭或无效的 rowid),操作可能会失败。

具有不同数据类型的 BLOB 长度

此示例显示了 __len__ 对不同二进制数据的行为方式。

data_types.py
import sqlite3
import pickle

with sqlite3.connect('datatypes.db') as conn:
    conn.execute("CREATE TABLE IF NOT EXISTS objects (id INTEGER PRIMARY KEY, obj BLOB)")
    
    # Store different Python objects as BLOBs
    objects = [
        pickle.dumps([1, 2, 3]),  # List
        pickle.dumps({'a': 1}),    # Dict
        pickle.dumps(3.14159),     # Float
        pickle.dumps("Hello"),     # String
        pickle.dumps(True)         # Boolean
    ]
    
    conn.executemany("INSERT INTO objects (obj) VALUES (?)", [(o,) for o in objects])
    
    # Check lengths of serialized objects
    cursor = conn.cursor()
    cursor.execute("SELECT rowid FROM objects ORDER BY rowid")
    for rowid, in cursor:
        with conn.blobopen('objects', 'obj', rowid, 'main') as blob:
            print(f"Object {rowid} serialized size: {len(blob)} bytes")

此示例使用 pickle 将不同的 Python 对象序列化为 BLOB,并检查它们的大小。__len__ 方法报告序列化的大小。

该示例演示了 __len__ 可以处理任何二进制数据,无论其原始 Python 类型或内容如何。

只读模式下的 BLOB 长度

此示例演示了将 __len__ 与只读 BLOB 一起使用。

readonly_blob.py
import sqlite3

with sqlite3.connect('readonly.db') as conn:
    conn.execute("CREATE TABLE IF NOT EXISTS archives (id INTEGER PRIMARY KEY, zip_data BLOB)")
    
    # Insert sample zip data
    zip_data = b'PK\x03\x04\x14\x00\x00\x00\x00\x00'  # Partial ZIP header
    conn.execute("INSERT INTO archives (zip_data) VALUES (?)", (zip_data,))
    
    # Open BLOB in read-only mode and check length
    with conn.blobopen('archives', 'zip_data', 1, 'main', readonly=True) as blob:
        print(f"ZIP data length: {len(blob)} bytes")
        
        try:
            blob.write(b'new data')  # Will fail
        except sqlite3.OperationalError as e:
            print(f"Expected error when writing: {e}")

此示例以只读模式打开 BLOB,并验证 __len__ 即使没有写权限也能正常工作。尝试修改 BLOB 会引发错误。

当您只需要检查 BLOB 元数据(如大小)而不修改内容时,只读模式非常有用。

最佳实践

资料来源

作者

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

列出所有 Python 教程