【问题标题】:sqlite3.ProgrammingError: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestringssqlite3.ProgrammingError:除非您使用可以解释 8 位字节串的 text_factory,否则不得使用 8 位字节串
【发布时间】:2011-03-26 09:59:00
【问题描述】:

在 Python 中使用 SQLite3,我正在尝试存储 UTF-8 HTML 代码的 sn-p 的压缩版本。

代码如下:

...
c = connection.cursor()
c.execute('create table blah (cid integer primary key,html blob)')
...
c.execute('insert or ignore into blah values (?, ?)',(cid, zlib.compress(html)))

在什么时候得到错误:

sqlite3.ProgrammingError: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings.

如果我使用 'text' 而不是 'blob' 并且不压缩 HTML sn-p,它可以正常工作(虽然 db 很大)。当我使用“blob”并通过 Python zlib 库进行压缩时,我收到上述错误消息。我环顾四周,但找不到一个简单的答案。

【问题讨论】:

    标签: python unicode sqlite zlib


    【解决方案1】:

    找到了解决方案,我应该多花点时间搜索一下。

    解决方案是将值“转换”为 Python 的“缓冲区”,如下所示:

    c.execute('insert or ignore into blah values (?, ?)',(cid, buffer(zlib.compress(html))))
    

    希望这对其他人有帮助。

    【讨论】:

    • 当我这样做时,我的数据库充满了 base36 文本,这会使数据库比直接存储 blob 更大。
    • 这是不正确的,你应该使用 sqlite3.Binary 来代替文档说的。
    • 看起来 sqlite3.Binary() 只是 buffer() 的别名,至少截至github.com/ghaering/pysqlite/blob/master/lib/dbapi2.py#L54
    • 嗯。而且看起来 pysqlite 文档的这一部分实际上鼓励使用 buffer():“因此可以毫无问题地将以下 Python 类型发送到 SQLite:......”[Python 类型] 缓冲区...... [SQLite 类型] BLOB"docs.python.org/2/library/sqlite3.html#introduction
    【解决方案2】:

    如果您想在 sqlite3 中使用 8 位字符串而不是 unicode 字符串,请为 sqlite 连接设置适当的 text_factory:

    connection = sqlite3.connect(...)
    connection.text_factory = str
    

    【讨论】:

    • 这可能会给您带来不同编码的问题,因为您仍在尝试将二进制数据解析为文本。最好改用 sqlite3.Binary。
    【解决方案3】:

    您可以使用 repr(html) 而不是原始输出来存储该值,然后在检索要使用的值时使用 eval(html)。

    c.execute('insert or ignore into blah values (?, ?)',(1, repr(zlib.compress(html))))
    

    【讨论】:

    • 像这样使用 eval 和 repr 很脏。无论您多么信任数据源。
    • 我同意,这里的任何东西都比 eval() 更好。正确的解决方案是使用 sqlite3.Binary,但如果由于某种原因不能,最好以更安全的方式对数据进行编码 - 例如使用 base64。
    【解决方案4】:

    为了使用 BLOB 类型,您必须首先将您的 zlib 压缩字符串转换为二进制数据 - 否则 sqlite 将尝试将其作为文本字符串处理。这是通过 sqlite3.Binary() 完成的。例如:

    c.execute('insert or ignore into blah values (?, ?)',(cid, 
    sqlite3.Binary(zlib.compress(html))))
    

    【讨论】:

    • 这行得通。但是,我想知道为什么需要这样做。 “BLOB”类型是否已经表明该列中的数据是二进制的?请注意,在 Python 2 中,字符串可以是文本或二进制。 sqlite3 不应该只将对象(zlib 压缩字符串)视为 BLOB 类型的二进制文件吗?
    • 我不认为 Python 在内存中拥有整个数据库模式来查询正确的数据类型 - 很可能它只是根据你传递的内容猜测运行时的类型,所以二进制字符串可以'不能与文本字符串区分开来。
    • 因为SQLite使用动态类型:sqlite.org/datatype3.html@user1783732
    【解决方案5】:

    语法:

    5 种可能的存储类型:NULL、INTEGER、TEXT、REAL 和 BLOB

    BLOB一般用于存放腌制模型或莳萝腌制模型

    > cur.execute('''INSERT INTO Tablename(Col1, Col2, Col3, Col4) VALUES(?,?,?,?)''', 
                                          [TextValue, Real_Value, Buffer(model), sqlite3.Binary(model2)])
    > conn.commit()
    
    > # Read Data:
    > df = pd.read_sql('SELECT * FROM Model, con=conn) 
    > model1 = str(df['Col3'].values[0]))
    > model2 = str(df['Col'].values[0]))
    

    【讨论】:

      猜你喜欢
      • 2011-08-02
      • 1970-01-01
      • 1970-01-01
      • 2014-07-15
      • 2011-02-19
      • 1970-01-01
      • 1970-01-01
      • 2013-04-26
      • 2011-06-17
      相关资源
      最近更新 更多