2010-08-06 74 views
78

在Python中使用SQLite3,我試圖存儲UTF-8 HTML代碼片段的壓縮版本。sqlite3.ProgrammingError:除非使用可解釋8位字節串的text_factory,否則不得使用8位字節串

代碼如下所示:

... 
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. 

如果我使用「文本」,而不是「斑點」和不壓縮的HTML代碼段,它工作正常(分貝是大雖然)。當我使用「blob」並通過Python zlib庫進行壓縮時,出現上述錯誤消息。我環顧四周,但找不到一個簡單的答案。

回答

34

找到了解決方案,我應該花費一點時間搜索。

解決辦法是「投」的值作爲一個Python「緩衝區」,像這樣:

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

希望這將幫助別人。

+11

您能否解釋爲什麼這會起作用? – Moshe 2013-04-08 14:58:25

+1

當我這樣做時,我的數據庫充滿了base36文本,這會使數據庫比直接存儲blob更大。 – 2014-03-06 19:04:39

+3

這是不正確的,你應該使用sqlite3.Binary來代替文檔說的。 – MarioVilas 2014-07-09 14:01:46

81

如果要使用8位的字符串,而不是在sqlite3的unicode字符串,設置approptiate text_factory SQLite的連接:

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

這可能會給你帶來不同編碼的問題,因爲你仍然試圖將二進制數據解析爲文本,最好使用sqlite3 .Binary改爲 – MarioVilas 2014-07-09 14:02:20

0

你可以使用再版(HTML)存儲值,而不是原始輸出和然後在檢索使用的值時使用eval(html)。

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

這樣使用eval和repr是非常髒的,無論你信任多少數據源。 – 2014-01-27 18:50:17

+0

我同意,任何東西都比eval()更好,正確的解決方案是使用sqlite3.Binary,但如果你不能出於某種原因,最好以更安全的方式對數據進行編碼 - 例如使用base64。 – MarioVilas 2014-07-09 14:04:03

30

爲了與BLOB類型的工作,你必須首先轉換您的zlib壓縮字符串轉換成二進制數據 - 否則sqlite的將嘗試處理它作爲一個文本字符串。這是用sqlite3.Binary()完成的。例如:

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

+1。這是**實際的**正確答案。 – Yuushi 2014-09-22 06:48:37

+0

This works。但是,我想知道爲什麼這個是需要的。是否有類型「BLOB」alr eady表示該列中的數據是二進制的?請注意,在Python 2中,字符串可以是文本或二進制。不應該sqlite3只是將對象(zlib壓縮字符串)視爲BLOB類型的二進制文件? – user1783732 2014-11-25 19:20:08

+0

我不認爲Python在內存中有整個數據庫模式來查詢正確的數據類型 - 很可能它只是基於傳遞它來猜測運行時類型,所以二進制字符串不能與文本字符串區分開來。 – MarioVilas 2014-12-25 11:46:45

相關問題