2013-10-30 174 views
1

我在寫一個C++數據轉換程序,它將數據從ODBC數據源複製到Oracle數據庫中。由於要移動的數據量非常大(數十億行),因此選擇了C++(包含數組操作)。Oracle OCI將無效的UTF8字符更改爲U + FFFD

現在文本列被假定爲UTF-8,但事實並非總是如此。當它不是我仍然想要將無效的原始字節複製到Oracle中時。我們將在稍後清理它們。該列是一個簡單的VARCHAR2(100),所以長度爲100個字節。但是Oracle似乎正在嘗試對數據進行某種UTF-8解析/處理。

例如下面的字符串(已經被截斷爲100個字節,因此無效):

Hex Bytes: 46 46 54 F0 9F 98 84 F0 9F 98 88 F0 9F 98 94 F0 9F 98 85 F0 9F 98 90 F0 9F 98 88 F0 9F 98 94 F0 9F 98 88 F0 9F 98 85 F0 9F 98 94 F0 9F 98 86 F0 9F 98 94 F0 9F 98 85 F0 9F 98 90 F0 9F 98 90 F0 9F 98 86 F0 9F 98 90 F0 9F 98 90 F0 9F 98 87 F0 9F 98 90 F0 9F 98 92 F0 9F 98 88 F0 9F 98 9A F0 9F 98 88 F0 

http://tinyurl.com/nhhkf62

實際上是被插入到數據庫中作爲:

Hex Bytes: 46 46 54 EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD 

http://tinyurl.com/orkv6z6

這基本上是前面的3個ASCII字符後跟每個後續字節的U + FFFD的UTF-8編碼。

其他詳情:

Oracle Version: 11g Enterprise Edition Release 11.2.0.1.0 
Oracle Client: oracle-instantclient11.2-basic-11.2.0.3.0-1 
Oracle OCI rpm: oracle-instantclient11.2-devel-11.2.0.3.0-1 
Environment: LANG=en_US.UTF-8 
Environment: NLS_CHARACTERSET=AMERICAN_AMERICA.UTF8 
Environment: NLS_LANG=AMERICAN.UTF8 

因此,沒有人知道爲什麼Oracle和/或OCI正在修改這些數據?有沒有辦法阻止它發生?

感謝

+1

什麼是數據庫字符集?如果你想存儲字節而不用擔心發生字符集轉換,你應該將數據存儲在'RAW(100)'列中,而不是'VARCHAR2(100)'。這是一個選擇嗎? –

+3

它們不是無效的UTF-8字符,而是不構成任何有效的UTF-8表示的字節。按照Unicode標準,在以UTF-8讀取數據時,用U + FFFD替換字符替換這些數據是正確的。所以如果你不想這樣做,你不能以這種方式讀取它,而是以原始的二進制數據讀取。 –

+0

不幸的是,我不認爲生吃是一種選擇,會把其他地方的東西置於危險之中。問題不在於閱讀,而是在插入。 「before」中的字節在插入的OCIStmtExecute之前立即從內存緩衝區轉儲。使用'dump(colname,16)'從db中提取「after」中的字節。 – Sodved

回答

0

NLS_LANG是隱式字符轉換最重要的。我認爲它應該是NLS_LANG = AMERICAN_AMERICA.UTF8而不是NLS_LANG = AMERICAN.UTF8

什麼是數據庫字符集?

+0

關閉,我不得不完全匹配數據庫的字符集。所以我設置了'NLS_LANG = AMERICAN.AL32UTF8',這一切都奏效了。謝謝你指點我在正確的方向 – Sodved

+0

啊好的。 AL32UTF8是較新的版本,允許更多(全部?)字符。 –

相關問題