问题现象
Oracle字符集为ZHS16GBK。
某表某字段中存入的字符串是UTF8编码(也是够了)。
直接选出查看是乱码,如下:
鎴戝氨鏄嚭鏉ユ墦閰辨补鐨勶紒
用C++等调用OCI接口选出后,可以转换编码。
用Java通过JDBC选出后,如果存在奇数汉字,则会丢失部分内容(部分乱码)。
用Toad工具查看会报Ora-29275
原因与分析
可能JDBC在用选出内容时已经做了字符编码的转换(而C++等低级语言OCI接口没有)
即使是指定为二进制,指定编码方式都不行。
导致UTF8的汉字3字节编码,被当成了Ansi的2字节编码,奇数汉字最后一个字节在转换中丢失。
XXX,YYY,ZZZ -> XX,XY,YY,ZZ (丢一个Z)
解决办法
由于无法修改存入数据库时的程序,只能选出时处理。
考虑从Oracle选出内容的时候直接转换为每个字节的ASCII码(字符方式展现10进制ASCII)。
再在程序中用这些ASCII码,合成原始字符串。
SQL代码
select dump(content,1010) as content from SomeTable
选出内容将从上列中的字符串
鎴戝氨鏄嚭鏉ユ墦閰辨补鐨勶紒
变成
Typ=1 Len=30 CharacterSet=ZHS16GBK:
230,136,145,229,176,177,230,152,175,229,135,186,230,157,165,230,137,147,233,133,177,…
Hint:Dump语句的参数请查看Oracle帮助文档,也可以 dump(xx,10,yy,zz)等等。
Java代码
String s = "Typ=1 Len=30 : 230,136,145,229,176,177,230,152,175,229,135,186,230,157,165,230,137,147......";
String[] a = s.split(":");
String[] b = a[1].split(",");
byte[] c = new byte[b.length];
for (int i = 0; i < b.length; i++) {
c[i]=(byte)Integer.parseInt(b[i].trim());
}
String d = new String(c, "UTF-8");
System.out.println(d);
上面为简单的例子,容错等自行考虑。。。
测试结果
鎴戝氨鏄嚭鏉ユ墦閰辨补鐨勶紒
恢复正常显示:
我就是出来打酱油的!