2009-08-12 67 views
1

我將jpeg圖像插入到我的UTF-8編碼Postgres數據庫到bytea列/ s中。我正在使用準備好的sql語句插入圖像。在聲明中,我在jpeg鏡像中創建了一個文件對象,然後將其作爲FileInputStream傳遞給setBinaryStream方法。但是每一個現在,再次執行該語句我的Java應用程序會拋出異常,指出:Postgres在通過Java插入圖像時編碼「UTF8」錯誤

「錯誤:無效字節序列編碼‘UTF8’:的0x84」

出現這種情況有選擇的幾個圖像這很奇怪。這些圖像是從前一組圖像中提取的,所有先前的圖像都插入了罰款,只有幾個提取的圖像似乎會導致錯誤。那麼我該如何解決這個問題呢?能夠以某種方式將字節流編碼爲UTF-8?或者它是數據庫的問題?

順便說一句,如果我用新的替換提取的圖像,並將它們保存爲JPEG,同樣的錯誤發生。謝謝你的幫助!

其代碼如下要求...

有一些代碼,否則缺少這將會是很長,但是,基本上我做的路徑和目錄名的幾項檢查,以確保他們遵守文件系統規則。這是一個遍歷所有子目錄的循環,並在所有子目錄中添加jpeg文件的所有 。然後我到帶有圖像子目錄的下一個目錄,直到沒有任何圖像。我還沒有添加嘗試捕獲和記錄部分。

String imgStr = image.toString(); 
int age = getAgeFromDir(imgStr); 
String gender = getSexFromDir(imgStr); 
String table = ""; 
switch(validIdx){ 
    case 0: table = "carpals"; 
     break; 
    case 1: table = "d_phalanges"; 
     break; 
    case 2: table = "p_phalanges"; 
     break; 
    case 3: table = "i_phalanges"; 
     break; 
    case 4: table = "epiphyses"; 
     break; 
    case 5: table = "sesamoids"; 
     break; 
    case 6: table = "metacarpals "; 
     break; 
} 

    PreparedStatement ps = con.prepareCall("INSERT INTO " + table + 
      " VALUES((SELECT hands.hand_id FROM hands WHERE hands.age = " + age + " AND hands.gender = '" + gender + "' AND hands.location = '" + path + directory + imageNames[i] + "')," + 
      " (SELECT COUNT(" + table + ".location) FROM " + table + "), " + 
      " ?, ?)" ); 

     //go through each sub-directory which contains jpeg images and add them to 
     //the database 
     File sublist = new File(image + "\\" + subdir[j]); 
     String[] files = sublist.list(); 
     String[] pics = sublist.list(new JpegFilter()); 

     if(files.length > pics.length){ 
      //WRITE TO LOG 
      //WARNING UNEXPECTED FILES OR DIRECTORIES FOUND IN.... 
     } 

      for(int r = 0; r < pics.length; r++){ 

        String location = image + "\\" + subdir[j] + "\\" + pics[r]; 
        System.out.println(i + "\t" + r + " location : " + location); 

        File f = new File(location); 
        FileInputStream pic = new FileInputStream(f); 


        if(f.isFile()){ 
        ps.setString(2, location); 
        ps.setBinaryStream(1, pic, (int)f.length()); 
        ps.execute(); 
        pic.close(); 
        } 
      } 
    ps.close(); 

}

引發的的SQLException低於,則在ps.execute()拋出:

異常在線程 「主」 org.postgresql.util.PSQLException:錯誤:無效字節序列用於編碼 「UTF8」:的0x84 在org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:1608) 在org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1343) 在org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl。的java:194) 在org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:451) 在org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:350) 在org.postgresql.jdbc2.AbstractJdbc2Statement。執行(AbstractJdbc2Statement.java:343) 在nuffielddb.HandDB.addExtractedImages(HandDB.java:406) 在nuffielddb.Main.main(Main.java:37) Java結果:1

+1

我們能看到你的代碼嗎? – 2009-08-12 14:55:57

+0

顯示打開文件並將其傳遞給JDBC的實際代碼,例外情況也很好看,例如,無論是扼流圈數據庫還是文件讀取失敗的數據庫。 – nos 2009-08-12 15:01:04

+0

你試圖插入圖像的列的類型是什麼?這是否是一次機會? – 2009-08-12 15:35:02

回答

2

嗯,是的0x84 不是有效的utf8字符:

=> perl -e 'print "\x84"' | iconv -f utf8 -t utf8 
iconv: illegal input sequence at position 0 

通常,bytea將與任何字節一起工作,但INSERT語句是文本字符串,因此必須符合客戶端的編碼!

插入數據的簡單方法:

  1. 編碼在應用程序中的數據是Base64格式(也有其他的選擇,但是這一次是最容易爲我展示)
  2. 插入與:INSERT INTO q(x)VALUES(decode(?'的base64'))在Perl(對不起,我不寫

實例的Java):

#!/usr/bin/perl 
use MIME::Base64; 
use DBI; 

my $dbh = DBI->connect("dbi:Pg:dbname=depesz;port=5840", "depesz"); 
my $blob = "\x84"; 
my $encoded = encode_base64($blob); 
$dbh->do("INSERT INTO q (x) VALUES (decode(?, 'base64'))", undef, $encoded); 

問表是:

 Table "public.q" 
Column | Type | Modifiers 
--------+-------+----------- 
x  | bytea | 

數據(插入後)的外觀像這樣:

# select x, octet_length(x) from q; 
    x | octet_length 
------+-------------- 
\x84 |   1 
(1 row) 
+0

好吧,我根本不知道Perl,但我想我得到了一般想法。我正確地假設我需要執行以下步驟: 1.獲取文件並創建一個字節數組 2.將字節數組中包含的文件存儲爲字節 3.將字節數組編碼爲'base64' 4 。然後嘗試執行SQL語句 問題,在您的代碼中執行'undef,$ encoded'是什麼? 是否有人知道如何將File對象分別轉換爲包含File對象的相應字節的字節數組? – binarycreations 2009-08-12 16:01:35

+0

undef不重要 - 它是一個DBI(Perl中的數據庫接口)的東西。 $ encoded是包含$ blob編碼(至base64)內容的變量。 和 - > do(sql,undef,$ some_variable),事情只是運行SQL代替$ some_variable而不是?在SQL中。 – 2009-08-12 16:48:02

1

那麼這就是那個窗口的想法(關於我的原始評論問題) - 顯然有一些編碼發生,某些圖像包含無效的字節序列,因此無法編碼,但我的推理原因是使用了clob(必須學會更仔細地閱讀該問題)。

我會忍不住爲Base64編碼流如果可能的話。

快速谷歌打開了這一點 - http://commons.apache.org/codec/api-release/org/apache/commons/codec/binary/Base64InputStream.html - 我懷疑可能是有用的(即使它只是爲靈感)。

+0

出於興趣,什麼導致這個無效的字節編碼。我有一個大的圖像,剪切和裁剪它的一小部分,然後我將兩個都添加到數據庫。較大的圖像插入罰款如何裁剪一個。我是否愚蠢地認爲較小的圖像不包含較大圖像的子集字節表示? – binarycreations 2009-08-12 16:07:10

+0

@格拉漢姆:我對圖像格式並不熟悉,但我不認爲大圖像的裁剪部分會轉換爲相同的字節序列 - 我認爲我說得對,大多數格式都採用某種形式壓縮將取決於每個像素值的頻率。例如,如果圖像整體大部分爲淺色,並且裁剪出較暗的區域,則可能會發生這種情況。 – 2009-08-12 16:16:48

+0

哦,所以問題可能是由於在jpeg格式中使用的壓縮創建了一個0x84的字節。所以也許改變它被壓縮多少可能也解決了這個問題,或者我吠叫了錯誤的樹? – binarycreations 2009-08-12 16:23:33

0

問題解決了:-)經過編碼和解碼不同的文件,我發現,發生同樣的SQL錯誤。我相信這個問題是由於FK屬性之一在我創建的Java應用程序中插入一些值後在Postgres數據庫中存儲了一個空值而發生的。當在子查詢中引用值hand_id時(如下):

(SELECT hands.hand_id FROM hands WHERE hands.age =「+ age +」AND hands.gender ='「+ gender +」'AND hands.location ='「+ path + directory + imageNames [i] +」')

當在Java中替換變量時,postgres返回的結果是某種空的不可返回字符,我相當於一個轉義字符或運輸在Java中返回(例如,「\」爲反斜槓)。在UTF-8值表和字符表示中查找字符後,該表顯示一個空格。

在上,我發現http://www.utf8-chartable.de/unicode-utf8-table.pl?utf8=0xthis網內查找的價值,它說的性格是:

Unicode value, Character, UTF-Hex, Name 

---------------------------------------------- 

U+0084,    ,0xc2 0x84,<control> 

注意字符是在表列是空的。

該問題是由於子查詢不包括必要的轉義字符造成的。 要解決此問題,必須將轉義字符添加到SQL子查詢中。在我的代碼,這意味着以下更改關於在最終的SQL語句的「hands.location」部分發生被髮送的:

BEFORE 

... hands.location = 'C:\directory\anotherdir\picture.jpg' 

AFTER 

... hands.location = E'C:\\directory\\anotherdir\\picture.jpg' 

那麼,什麼是我學習的功課?

  1. 經常檢查你的SQL語句,即使你認爲它是正確的

  2. 當插入字符串到VARCHAR列記所需要的不同的轉義字符,首開引號前放置一個é (如此,E')。請記住,反斜槓需要添加兩個反斜槓(因此,E'\')

  3. 如果您確實遇到數據庫編碼問題,那麼您可以隨時嘗試並重新定義數據庫是否在配置中編碼將數據轉換並編碼爲所需的編碼,以便數據庫可以接受。

  4. APACHE COMMONS作爲Java的有用base64編碼編解碼器。非常有用,必須記住以後的日子。

  5. 錯誤確實可以在最好的時候欺騙。如果你得到這個錯誤,你必須先檢查我所做的所有事情。

順便說一句,感謝所有發佈答案的人。我總是非常慷慨地放棄他們的時間來幫助別人!它真的很有用,並證明了爲什麼StackOverflow能夠很好地工作! :-)

相關問題