采用二进制表示设计通讯录数据库的Python实现思路是否正确?
你的实现思路存在几个关键问题
嘿,你的核心想法(用二进制格式存储通讯录数据)本身没问题,但目前的实现方式绕了弯路,还会给后续的数据操作带来一堆麻烦,具体问题如下:
1. 完全没必要手动把数据转成二进制字符串
SQLite这类关系型数据库本身就会自动处理数据的底层二进制存储。比如你定义的INTEGER、VARCHAR类型,数据库引擎会以高效的二进制格式来存储它们,根本不需要你手动把整数转成bin()返回的"0b10"这类字符串,也不需要把字符串拆成字节再拼接成二进制字符串。
你现在把所有数据都转成了字符串类型存入数据库,比如原本的整数user_id变成了"0b1",这会导致:
- 无法直接对
user_id做数值运算(比如排序、范围查询) - 浪费存储空间:二进制字符串比原生数值/字符串占用更多字节
- 后续读取数据时,还要自己写复杂的代码把这些二进制字符串还原成原数据,非常繁琐
2. 字符串转二进制的方式不合理
你把字符串转成bytearray后,每个字节调用bin()再拼接,比如"USER1"会变成一串类似0b101010100b1001010...的字符串,这种格式:
- 没有分隔符,还原时很难准确拆分每个字节的二进制内容
- 存储的是文本形式的二进制描述,不是真正的二进制字节流,完全失去了二进制存储的意义
正确的实现思路
如果你确实想以二进制格式存储(比如需要自定义序列化、加密场景),应该用SQLite的BLOB类型来存储二进制数据,而不是转成字符串。但对于普通通讯录场景,直接用SQLite的原生类型存储是最简单高效的:
修正后的代码示例
import sqlite3 as lite con = lite.connect('address_book.db') cur = con.cursor() # 直接使用原生类型的数据,不需要手动转二进制 users = ( (1, 'USER1', 'Surname1', 'Address1'), (2, 'USER2', 'Surname2', 'Address2'), ) cur.execute("DROP TABLE IF EXISTS users") cur.execute(""" CREATE TABLE IF NOT EXISTS users( user_id INTEGER PRIMARY KEY, first_name VARCHAR(20) NOT NULL, last_name VARCHAR(20) NOT NULL, address VARCHAR(20) NOT NULL ) """) # 直接插入原生数据,sqlite3会自动处理存储格式 cur.executemany("INSERT INTO users VALUES(?, ?, ?, ?)", users) con.commit() # 验证读取是否正常 cur.execute("SELECT * FROM users WHERE user_id = 1") print(cur.fetchone()) # 输出 (1, 'USER1', 'Surname1', 'Address1'),和原数据一致
如果确实需要二进制存储(比如自定义序列化)
如果因为某些特殊需求必须手动处理二进制,可以用pickle把数据序列化字节流,然后存入BLOB字段:
import pickle import sqlite3 as lite con = lite.connect('address_book.db') cur = con.cursor() cur.execute("DROP TABLE IF EXISTS users_blob") cur.execute(""" CREATE TABLE IF NOT EXISTS users_blob( user_id INTEGER PRIMARY KEY, user_data BLOB NOT NULL ) """) users = ( (1, 'USER1', 'Surname1', 'Address1'), (2, 'USER2', 'Surname2', 'Address2'), ) # 把用户数据序列化二进制字节流 for user_id, fname, lname, addr in users: user_data = pickle.dumps((fname, lname, addr)) cur.execute("INSERT INTO users_blob VALUES(?, ?)", (user_id, user_data)) con.commit() # 读取时反序列化 cur.execute("SELECT user_data FROM users_blob WHERE user_id = 1") data = cur.fetchone()[0] print(pickle.loads(data)) # 输出 ('USER1', 'Surname1', 'Address1')
总结一下:你的核心需求(二进制存储)可以通过数据库原生的BLOB类型或序列化工具实现,但手动转二进制字符串的做法是不必要的,反而会引入更多问题。
内容的提问来源于stack exchange,提问作者Ren
相关产品推荐
相关产品推荐

