我在写一个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