2010-08-06 6 views
78

Mit SQLite3 in Python versuche ich, eine komprimierte Version eines Codefragments von UTF-8 zu speichern.sqlite3.ProgrammingError: Sie dürfen keine 8-bit Bytestrings verwenden, außer Sie verwenden eine text_factory, die 8-bit Bytestrings interpretieren kann

-Code sieht wie folgt aus:

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

An welchem ​​Punkt an den Fehler:

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. 

Wenn ich 'Text' und nicht als 'Blob' verwenden und nicht komprimiere den HTML-Snippet es funktioniert alles gut (db ist zu groß obwohl). Wenn ich 'Blob' verwende und über Python zlib library komprimiere, erhalte ich die obige Fehlermeldung. Ich schaute mich um, konnte aber keine einfache Antwort finden.

Antwort

34

Die Lösung gefunden, hätte ich nur ein wenig mehr Zeit mit der Suche verbracht.

Lösung ist zu ‚werfen‘ den Wert als ‚Puffer‘ Python, etwa so:

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

Hoffentlich jemand anderes helfen.

+11

Können Sie erklären, warum das funktioniert? – Moshe

+1

Wenn ich dies tat, war meine Datenbank voll mit base36-Text, der die Datenbank größer machen würde, als den Blob direkt zu speichern. –

+3

Das ist falsch, Sie sollten stattdessen sqlite3.Binary verwenden, wie es in der Dokumentation heißt. – MarioVilas

81

Wenn Sie 8-Bit-Strings in sqlite3 statt Unicode-String verwenden, setzen Sie approptiate text_factory für SQLite-Anschluss:

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

Dies kann zu Problemen mit verschiedenen Codierungen führen, da Sie immer noch versuchen, binäre Daten als Text zu analysieren. Am besten verwenden Sie sqlite3 .Binary statt. – MarioVilas

0

Sie den Wert speichern könnte repr (html) anstelle des Rohausgangssignal und Verwenden Sie dann eval (html), wenn Sie den zu verwendenden Wert abrufen.

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

Verwendung von eval und repl wie dies ist sehr schmutzig.Wie auch immer Sie einer Datenquelle vertrauen. –

+0

Ich stimme zu, alles ist besser als eval() hier. Die richtige Lösung ist mit sqlite3.Binary, aber wenn Aus irgendeinem Grund ist es besser, die Daten auf eine sicherere Art und Weise zu verschlüsseln - zum Beispiel mit base64. – MarioVilas

30

Um mit dem BLOB-Typ zu arbeiten, müssen Sie zunächst Ihre zlib komprimierte String in binäre Daten umwandeln - sonst wird versuchen SQLite es als Textzeichenfolge zu verarbeiten. Dies geschieht mit sqlite3.Binary(). Zum Beispiel:

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

+1. Dies ist die ** tatsächliche ** richtige Antwort. – Yuushi

+0

das funktioniert. Allerdings habe ich mich gefragt, warum dies wird benötigt .. Hat der Typ "BLOB" alr Bitte geben Sie an, dass die Daten in dieser Spalte binär sind. Hinweis: In Python 2 kann die Zeichenfolge entweder Text oder Binär sein. Sollte sqlite3 nicht einfach das Objekt (zlib compressed string) als Binärcode für den BLOB-Typ behandeln? – user1783732

+0

Ich glaube nicht, dass Python das gesamte Datenbankschema im Speicher hat, um die richtigen Datentypen zu konsultieren - höchstwahrscheinlich werden die Typen nur zur Laufzeit auf der Grundlage Ihrer Übergabe geschätzt, sodass eine Binärzeichenfolge nicht von einer Textzeichenfolge unterschieden werden kann . – MarioVilas

Verwandte Themen