Java中的字符串转码处理

    又是字符串,看似简单的问题,却总是出错,以前是C,然后是VB,进而是COM提供的BSTR,似乎每门语言在
字符串的处理上都有各自之道,这不,到了Java,字符串又给我带来麻烦。
    碰到的问题:
        服务端通过Web获取用户选择的账套名称,为了使用第三方的JCR实现库,必须将账套名称作为参数写
到相关的xml中,第三方库会从xml中读取该参数,进一步生成connection使用。在中文操作系统的服务器上运行
正常,但是在英文操作系统下,如果传入的账套名为中文,则在xml中的账套名的中文部分被存为??。
    问题解决过程:
    第一步:
        :添加log,我想看一下从web端获取的账套名称。
        :通过日志文件,发现在日志文中取得的账套名的中文部分同样变为了??。
    判断:难道是web页面中取得账套名已经错了?不可能,因为系统其它地方大量用到该账套名,不可能有问题。
        或许是在写入时,转码出错。
    第二步: 
        :修改log,改成 账套名.getBytes(),然后将byte逐个转为16进制显示的字串。
        :查看结果,中文部分已经是3F 3F。(?的ASCII码)
    判断:问题应该出在系统在执行getBytes时的转码,噢,明白了,系统当前的字符集是ISO8859_1(ASCII),不
          支持中文转换。
    第三步: 
 :改成 账套名.getBytes("UTF-8"),
        :查看结果,中文部分没有丢失转码,获得了正确的UTF-8编码。
    解决方法:
 添加encode方法,将中文字符串转换为UTF-8编码,然后格式化为字串方式。
        添加decode方法,将字串转回中文。

    问题的解决过程很简单,但在处理问题时,了解了Java字串的一些原理。
    1:java对于String的存储,与C++的char * 和COM的BSTR一样,只保存字节流,不包含编码信息。
       但是,在java的内核存储时,采用了统一的Unicode的(UTF16编码),也就是一个字符采用固定的两字节存储。
    2:java的String在进行任何转换时,由于1的存储方式,那么,源编码是UTF16,目的字符串必须指定,否则,采用默认。
    3:系统默认的字符集,是取JVM中的file.encoding属性,该属性依赖于具体的操作系统。
    4:如果目的字符集找不到对应的转码,如采用ISO8859_1来转换中文,会变为3F(?)。

    附:关于UTF-16,还会有前缀,叫做BOM。大致作用如下:
    UTF的字节序和BOM
    UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?
    Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:在UCS编码中有一个叫做”ZERO WIDTH NO-BREAK SPACE”的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符”ZERO WIDTH NO-BREAK SPACE”。
    这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符”ZERO WIDTH NO-BREAK SPACE”又被称作BOM。
    UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符”ZERO WIDTH NO-BREAK SPACE”的UTF-8编码是EF BB BF。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。
    Windows就是使用BOM来标记文本文件的编码方式的。


你可能感兴趣的:(java,xml,Web,windows,String,存储)