用Python将二进制文件插入SQLite数据库
我正在尝试写一个简单的Python脚本,把.odt文档插入到SQLite数据库里。到目前为止,我做了这些,但似乎没有成功:
f=open('Loremipsum.odt', 'rb')
k=f.read()
f.close()
cursor.execute="INSERT INTO notes (note) VALUES ('%s')" %(sqlite.Binary(k))
cursor.close()
conn.close()
我没有收到任何错误信息,但从我看到的情况来看,记录并没有被插入。我哪里做错了?另外,我该如何把存储的文档提取出来呢?谢谢!
3 个回答
9
问题:
你没有展示你运行的完整代码。不要让回答的人去猜像
sqlite.Binary(k)
这样的东西是什么。根本问题:你没有提交你的事务。 在
conn.close()
之前要使用conn.commit()
。
13
这个例子有几个问题,我会一个一个来讲。
- 没有错误检查。我们需要使用try/except/finally结构,或者用
with
关键字。 - Python的方法和C#的属性不一样。你不是在运行
execute
方法,而是在给一个对象赋值一个字符串。(在Python中,方法也是对象。) - 非常重要的一点是,你的代码容易受到SQL注入攻击。我们绝对不应该用Python的字符串操作来构建SQL语句。我们应该始终使用占位符。
- 这个例子不完整,这会导致一个棘手的问题。假设有一个
CREATE TABLE
语句,那么会创建一个新的隐式事务。必须发出commit
语句才能把数据保存到数据库文件中。在SQLite中,除了SELECT
以外的任何语句都会开始一个隐式事务。(有些数据库,比如MySQL,默认是自动提交模式,但SQLite不是。)
下面是一个正确的示例,它将一个LibreOffice文档写入SQLite数据库的docs
表:
#!/usr/bin/env python
import sqlite3
def readData():
fl = open('book.odt', 'rb')
with fl:
data = fl.read()
return data
con = sqlite3.connect('test.db')
with con:
cur = con.cursor()
cur.execute("CREATE TABLE IF NOT EXISTS docs(Data BLOB)")
data = readData()
sql = "INSERT INTO docs(Data) VALUES (?)"
cur.execute(sql, (sqlite3.Binary(data), ))
book.odt文件位于当前工作目录中。我们没有手动调用commit
方法,因为这由with
关键字在后台处理。
编辑去掉了lite别名
37
我不太确定你用的 sqlite.Binary
是什么,不过没关系,这里有个可以运行的例子:
import sqlite3
# let's just make an arbitrary binary file...
with open('/tmp/abin', 'wb') as f:
f.write(''.join(chr(i) for i in range(55)))
# ...and read it back into a blob
with open('/tmp/abin', 'rb') as f:
ablob = f.read()
# OK, now for the DB part: we make it...:
db = sqlite3.connect('/tmp/thedb')
db.execute('CREATE TABLE t (thebin BLOB)')
db.execute('INSERT INTO t VALUES(?)', [buffer(ablob)])
db.commit()
db.close()
# ...and read it back:
db = sqlite3.connect('/tmp/thedb')
row = db.execute('SELECT * FROM t').fetchone()
print repr(str(row[0]))
在 Python 2.6 下运行这段代码时,结果会显示出你预期的内容:
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456'
注意,在插入二进制大对象(blob)时需要用到 buffer
,而读取时则用 str
来把它转回字符串(因为读取的结果也是 buffer
类型)——如果你只是想把它写到磁盘上,后面的这一步就不需要了(因为文件的 write
方法既可以接受 buffer
对象,也可以接受字符串)。