2014-06-12 21 views
7

Zrobiłem sporo spostrzeżenia na temat tego błędu i sprowadziłem to do faktu, że bazy danych, z którymi pracuję, są w różnych kodowaniach.psycopg2.DataError: niepoprawna sekwencja bajtów dla kodowania "UTF8": 0xa0

Serwer AIX Pracuję z działa

psql 8.2.4 

server_encoding     | LATIN1   |  | Client Connection Defaults/Locale and Formatting    | Sets the server (database) character set encoding. 

okien 2008 R2 serwera Pracuję z działa

psql (9.3.4)

CREATE DATABASE postgres 
WITH OWNER = postgres 
    ENCODING = 'UTF8' 
    TABLESPACE = pg_default 
    LC_COLLATE = 'English_Australia.1252' 
    LC_CTYPE = 'English_Australia.1252' 
    CONNECTION LIMIT = -1; 

COMMENT ON DATABASE postgres 
IS 'default administrative connection database'; 

Teraz kiedy próbuję wykonać mój skrypt poniżej Pythona Otrzymuję ten błąd

Traceback (most recent call last): 
File "datamain.py", line 39, in <module> 
sys.exit(main()) 
File "datamain.py", line 33, in main 
write_file_to_table("cms_jobdef.txt", "cms_jobdef", con_S104838) 
File "datamain.py", line 21, in write_file_to_table 
cur.copy_from(f, table, ",") 
psycopg2.DataError: invalid byte sequence for encoding "UTF8": 0xa0 
CONTEXT: COPY cms_jobdef, line 15209  

Oto mój skrypt

import psycopg2 
import StringIO 
import sys 
import pdb 

def connect_db(db, usr, pw, hst, prt): 
    conn = psycopg2.connect(database=db, user=usr, 
    password=pw, host=hst, port=prt) 
    return conn 

def write_table_to_file(file, table, connection): 
    f = open(file, "w") 
    cur = connection.cursor() 
    cur.copy_to(f, table, ",") 
    f.close() 
    cur.close() 

def write_file_to_table(file, table, connection): 
    f = open(file,"r") 
    cur = connection.cursor() 
    cur.copy_from(f, table, ",") 
    f.close() 
    cur.close() 

def main(): 
    login = open('login.txt','r') 
    con_tctmsv64 = connect_db("x", "y", 
    login.readline().strip(), 
    "d.domain", "c") 
    con_S104838 = connect_db("x", "y", "z", "a", "b") 
    try: 
     write_table_to_file("cms_jobdef.txt", "cms_jobdef", con_tctmsv64) 
     write_file_to_table("cms_jobdef.txt", "cms_jobdef", con_S104838) 
    finally: 
     con_tctmsv64.close() 
     con_S104838.close() 

if __name__ == "__main__": 
    sys.exit(main()) 

zostały usunięte niektóre dane wrażliwe.

Więc nie jestem pewien, jak mogę kontynuować. O ile mogę powiedzieć, że metoda copy_expert może pomóc, eksportując jako kodowanie UTF8. Ale ponieważ serwer, z którego pobieram dane, działa 8.2.4 Nie sądzę, że obsługuje format kodowania COPY.

Myślę, że moim najlepszym strzałem jest próba ponownej instalacji bazy danych postgre z kodowaniem LATIN1 na serwerze Windows. Kiedy próbuję to zrobić, otrzymuję poniższy błąd.

psql error

Więc im zupełnie zatrzymany, każda pomoc będzie bardzo mile widziane!

Aktualizacja Zainstalowałem postgre db w oknach jako kodowanie LATIN1, zmieniając domyślny lokalny na "C". Ten jednak dał mi poniższy błąd i nie robi wydaje się prawdopodobne udanej/prawidłowego podejścia

enter image description here

Próbowałem również kodowania plików w formacie binarnym za pomocą psql COPY funkcję

def write_table_to_file(file, table, connection): 
    f = open(file, "w") 
    cur = connection.cursor() 
    #cur.copy_to(f, table, ",") 
    cur.copy_expert("COPY cms_jobdef TO STDOUT WITH BINARY", f) 
    f.close() 
    cur.close() 

def write_file_to_table(file, table, connection): 
    f = open(file,"r") 
    cur = connection.cursor() 
    #cur.copy_from(f, table) 
    cur.copy_expert("COPY cms_jobdef FROM STDOUT WITH BINARY", f) 
    f.close() 
    cur.close() 

nadal nie ma szczęścia Pojawia się ten sam błąd:

DataError: invalid byte sequence for encoding "UTF8": 0xa0 
CONTEXT: COPY cms_jobdef, line 15209, column descript 

W odniesieniu do odpowiedzi Phils próbowałem tego podejścia z wciąż nie ma su ccess.

import psycopg2 
import StringIO 
import sys 
import pdb 
import codecs 

def connect_db(db, usr, pw, hst, prt): 
    conn = psycopg2.connect(database=db, user=usr, 
    password=pw, host=hst, port=prt) 
    return conn 

def write_table_to_file(file, table, connection): 
    f = open(file, "w") 
    #fx = codecs.EncodedFile(f,"LATIN1", "UTF8") 
    cur = connection.cursor() 
    cur.execute("SHOW client_encoding;") 
    print cur.fetchone() 
    cur.copy_to(f, table) 
    #cur.copy_expert("COPY cms_jobdef TO STDOUT WITH BINARY", f) 
    f.close() 
    cur.close() 

def write_file_to_table(file, table, connection): 
    f = open(file,"r") 
    cur = connection.cursor() 
    cur.execute("SET CLIENT_ENCODING TO 'LATIN1';") 
    cur.execute("SHOW client_encoding;") 
    print cur.fetchone() 
    cur.copy_from(f, table) 
    #cur.copy_expert("COPY cms_jobdef FROM STDOUT WITH BINARY", f) 
    f.close() 
    cur.close() 

def main(): 
    login = open('login.txt','r') 
    con_tctmsv64 = connect_db("x", "y", 
    login.readline().strip(), 
    "ctmtest1.int.corp.sun", "5436") 
    con_S104838 = connect_db("x", "y", "z", "t", "5432") 
    try: 
     write_table_to_file("cms_jobdef.txt", "cms_jobdef", con_tctmsv64) 
     write_file_to_table("cms_jobdef.txt", "cms_jobdef", con_S104838) 
    finally: 
     con_tctmsv64.close() 
     con_S104838.close() 

if __name__ == "__main__": 
    sys.exit(main()) 

wyjście

In [4]: %run datamain.py 
('sql_ascii',) 
('LATIN1',) 

In [5]: 

ta zakończy się pomyślnie, ale kiedy uruchomić

select * from cms_jobdef; 

Nic nie jest w nowej bazie danych

enter image description here

Próbowałem nawet konwertować format pliku z LATIN1 na UTF8.Nadal nie ma szczęścia

Dziwne jest to, że robię to ręcznie, używając tylko funkcji postgre COPY, która działa. Nie mam pojęcia dlaczego. Po raz kolejny wszelka pomoc byłaby bardzo doceniana.

Odpowiedz

4

Jestem w procesie migracji z bazy danych SQL_ASCII do bazy UTF8, i wpadł na ten sam problem. Na podstawie this answer, po prostu dodaje to oświadczenie do początku mojego skryptu importu:

set client_encoding to 'latin1' 

i wszystko wydaje się być importowany poprawnie.

+0

Cześć Phil, dziękuję za odpowiedź. Próbowałem również i nie odniosłem sukcesu. Kod zostanie pomyślnie wykonany, ale po uruchomieniu tabela pozostanie pusta. Zaktualizowałem moje oryginalne pytanie, aby odzwierciedlić to –

+1

Nienawidzę pytać o to ... Czy zgadzasz się na transakcję? http://initd.org/psycopg/docs/connection.html mówi: "Domyślnie Psycopg otwiera transakcję przed wykonaniem pierwszego polecenia: jeśli funkcja commit() nie zostanie wywołana, efekt jakiejkolwiek manipulacji danymi zostanie utracony." –

+0

Dzięki za opinie Phil, byłeś ogromną pomocą! –

4

Okazało się, że jest kilka opcji rozwiązania tego problemu.

Opcja zmiany kodowania klientów sugerowana przez Phila działa.

cur.execute("SET CLIENT_ENCODING TO 'LATIN1';") 

Inną opcją jest konwersja danych w locie. W tym celu użyłem modułu Pythona o nazwie kodeki.

f = open(file, "w") 
fx = codecs.EncodedFile(f,"LATIN1", "UTF8") 
cur = connection.cursor() 
cur.execute("SHOW client_encoding;") 
print cur.fetchone() 
cur.copy_to(fx, table) 

Kluczem linia jest

fx = codecs.EncodedFile(f,"LATIN1", "UTF8") 

Moim głównym problemem było to, że nie było popełnienie moje zmiany w bazie danych! Głupi mnie :)