2010-08-06 10 views
78

Używając SQLite3 w Pythonie, próbuję przechowywać skompresowaną wersję fragmentu kodu HTML UTF-8.sqlite3.ProgrammingError: Nie wolno używać 8-bitowych bytestrings, chyba że używasz text_factory, który może interpretować 8-bitowe bytestrings

Kod wygląda następująco:

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

W tym momencie co pojawia się błąd:

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. 

Jeśli użyję 'text' zamiast 'blob' i nie ściskać fragment kodu HTML , działa dobrze (db jest do dużych). Kiedy używam "blob" i kompresuję przez bibliotekę zlib Pythona, pojawia się powyższy komunikat o błędzie. Rozejrzałem się, ale nie mogłem znaleźć prostej odpowiedzi.

Odpowiedz

34

Znaleziono rozwiązanie, powinienem poświęcić trochę więcej czasu na wyszukiwanie.

Rozwiązanie jest „Cast” wartości jako „bufor” pyton, tak:

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

Mamy nadzieję, że pomoże to ktoś inny.

+11

Czy możesz wyjaśnić, dlaczego to działa? – Moshe

+1

Kiedy to zrobiłem, moja baza danych była pełna tekstu base36, co spowodowałoby, że baza danych byłaby większa niż bezpośrednio przechowująca blob. –

+3

To jest nieprawidłowe, powinieneś używać sqlite3.Binary zamiast tego, jak mówi dokumentacja. – MarioVilas

81

Jeśli chcesz użyć 8-bitowe ciągi zamiast ciąg Unicode w sqlite3, ustawianie approptiate text_factory SQLite połączenia:

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

Może to powodować problemy z różnymi kodowaniami, ponieważ nadal próbujesz parsować dane binarne jako tekst. Najlepiej użyć sqlite3 .Binary zamiast tego – MarioVilas

0

Mogłeś zapisać wartość za pomocą repr (HTML) zamiast wyjścia surowego i następnie użyj eval (html) podczas pobierania wartości do użycia.

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

Używanie eval i repr jak to jest bardzo brudne Nie ważne ile ufasz danych-źródła danych –

+0

Zgadzam się, wszystko jest lepsze niż eval() tutaj .Właściwe rozwiązanie używa sqlite3.Binary, ale jeśli nie możesz z jakiegoś powodu, lepiej kodować dane w bezpieczniejszy sposób - na przykład z base64. – MarioVilas

30

Aby pracować z typu BLOB, należy najpierw przekonwertować ciąg zlib skompresowane do danych binarnych - inaczej sqlite postara się przetworzyć go jako ciąg tekstowy. Odbywa się to za pomocą sqlite3.Binary(). Na przykład:

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

+1 To jest ** aktualna ** poprawna odpowiedź – Yuushi

+0

to działa, ale zastanawiałem się, dlaczego to jest potrzebny. Czy typ "BLOB" alr eady wskazują, że dane w tej kolumnie są binarne? Uwaga w Pythonie 2 łańcuch może być tekstowy lub binarny. Czy plik sqlite3 nie powinien traktować obiektu (skompresowany ciąg zlib) jako binarny dla typu BLOB? – user1783732

+0

Nie sądzę, że Python ma cały schemat bazy danych w pamięci, aby sprawdzać poprawne typy danych - najprawdopodobniej po prostu zgaduje typy w środowisku wykonawczym w oparciu o to, co przekazujesz, więc ciąg binarny nie może być odróżniany od ciągu tekstowego . – MarioVilas

Powiązane problemy