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__ 方法检查其长度。
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 的行为方式。
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 的长度。
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 长度。
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__ 时的错误情况。
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__ 对不同二进制数据的行为方式。
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 一起使用。
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 元数据(如大小)而不修改内容时,只读模式非常有用。
最佳实践
- 始终关闭 BLOB 对象: 使用上下文管理器进行自动清理
- 在读取之前检查长度: 避免缓冲区溢出
- 优雅地处理错误: BLOB 操作可能会失败
- 用于大型二进制文件: BLOB 非常适合大型数据
- 考虑内存使用情况: 长度检查不会加载内容
资料来源
作者
列出所有 Python 教程。