sqlite3.ProgrammingError: 8 bitlik bytestrings'i yorumlayabilen bir text_factory kullanmadığınız sürece 8 bitlik bytestrings kullanmamalısınız.


90

Python'da SQLite3 kullanarak, UTF-8 HTML kod parçacığının sıkıştırılmış bir sürümünü saklamaya çalışıyorum.

Kod şuna benzer:

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

Hangi noktada hatayı alırsınız:

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.

"Blob" yerine "metin" kullanırsam ve HTML parçacığını sıkıştırmazsam, her şey yolunda gider (db olsa da büyüktür). 'Blob' kullandığımda ve Python zlib kitaplığı aracılığıyla sıkıştırdığımda, yukarıdaki hata mesajını alıyorum. Etrafa baktım ama bunun için basit bir cevap bulamadım.

Yanıtlar:


94

Sqlite3'te unicode dizesi yerine 8 bitlik dizeler kullanmak istiyorsanız, sqlite bağlantısı için uygun text_factory ayarlayın:

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

7
Hala ikili verileri metin olarak ayrıştırmaya çalıştığınız için, bu size farklı kodlamalarla ilgili sorunlar verebilir. Bunun yerine sqlite3.Binary kullanmak en iyisidir.
MarioVilas

35

Çözümü buldum, araştırmaya biraz daha zaman harcamalıydım.

Çözüm, değeri bir Python 'tamponu' olarak 'çevirmektir, örneğin:

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

Umarım bu başka birine yardımcı olur.


1
Bunu yaptığımda, veritabanım base36 metniyle doluydu, bu da veritabanını blob'u doğrudan depolamaktan daha büyük hale getirir.
Brian Minton

3
Bu yanlış, dokümantasyonda belirtildiği gibi bunun yerine sqlite3.Binary kullanmalısınız.
MarioVilas


Huh. Ayrıca, pysqlite belgelerinin bu bölümü aslında buffer () kullanımını teşvik ediyor gibi görünüyor: "Aşağıdaki Python türleri böylece sorunsuz bir şekilde SQLite'a gönderilebilir: ..." [Python türü] arabellek ... [SQLite türü] BLOB " docs.python.org/2/library/sqlite3.html#introduction
stevegt

35

BLOB türü ile çalışmak için, önce zlib sıkıştırılmış dizenizi ikili verilere dönüştürmelisiniz - aksi takdirde sqlite bunu bir metin dizesi olarak işlemeye çalışır. Bu, sqlite3.Binary () ile yapılır. Örneğin:

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

bu çalışıyor. Ancak bunun neden gerekli olduğunu merak ediyordum. "BLOB" türü zaten bu sütundaki verilerin ikili olduğunu gösteriyor mu? Python 2'de dizenin metin veya ikili olabileceğini unutmayın. Sqlite3'ün nesneyi (sıkıştırılmış zlib dizesi) BLOB türü için ikili olarak ele alması gerekmez mi?
user1783732

Python'un, doğru veri türlerine başvurmak için tüm veritabanı şemasının bellekte olduğunu düşünmüyorum - büyük olasılıkla, ilettiklerinize bağlı olarak çalışma zamanındaki türleri tahmin eder, bu nedenle ikili bir dizge bir metin dizesinden ayırt edilemez.
MarioVilas

SQLite dinamik tür kullandığı için: sqlite.org/datatype3.html @ user1783732
Lester Cheung

1

Sözdizimi:

5 tür olası depolama: NULL, INTEGER, TEXT, REAL ve BLOB

BLOB genellikle turşu modellerini veya dereotu turşulu modellerini saklamak için kullanılır.

> 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]))

0

Değeri ham çıktı yerine repr (html) kullanarak depolayabilir ve daha sonra kullanım için değeri alırken eval (html) kullanabilirsiniz.

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

1
Eval ve repr'i bu şekilde kullanmak çok kirli. Bir veri kaynağına ne kadar güvendiğiniz önemli değil.
Jason Fried

Katılıyorum, burada her şey eval () dan daha iyidir. Doğru çözüm sqlite3.Binary kullanmaktır, ancak herhangi bir nedenle yapamıyorsanız, verileri daha güvenli bir şekilde kodlamak daha iyidir - örneğin base64 ile.
MarioVilas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.