我在寫一個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
實際上是被插入到數據庫中作爲:
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
這基本上是前面的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正在修改這些數據?有沒有辦法阻止它發生?
感謝
什麼是數據庫字符集?如果你想存儲字節而不用擔心發生字符集轉換,你應該將數據存儲在'RAW(100)'列中,而不是'VARCHAR2(100)'。這是一個選擇嗎? –
它們不是無效的UTF-8字符,而是不構成任何有效的UTF-8表示的字節。按照Unicode標準,在以UTF-8讀取數據時,用U + FFFD替換字符替換這些數據是正確的。所以如果你不想這樣做,你不能以這種方式讀取它,而是以原始的二進制數據讀取。 –
不幸的是,我不認爲生吃是一種選擇,會把其他地方的東西置於危險之中。問題不在於閱讀,而是在插入。 「before」中的字節在插入的OCIStmtExecute之前立即從內存緩衝區轉儲。使用'dump(colname,16)'從db中提取「after」中的字節。 – Sodved