2013-10-30 167 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是较新的版本,允许更多(全部?)字符。 –

相关问题