Unicode、UTF-8、UTF-16字符编码的那点事

  相信不少人被字符乱码的问题给困扰过。字符编码,确实是一个碍手的事。在这里写一下这三种编码的那点事。
  首先看一下下面的程序
        System.out.println("a(Unicode)    :" + "a".getBytes("Unicode").length);
        System.out.println("a(Unicode)    :" + "aa".getBytes("Unicode").length);
        System.out.println(" (Unicode)   :" + "呃".getBytes("Unicode").length);
        System.out.println(" 呃呃(Unicode) :" + "呃呃.getBytes("Unicode").length);
        System.out.println("");
        System.out.println("a(UTF-8)    :" + "a".getBytes("UTF-8").length);
        System.out.println("aa(UTF-8)   :" + "aa".getBytes("UTF-8").length);
        System.out.println(" (UTF-8)   :" + "  ".getBytes("UTF-8").length);
        System.out.println(" 呃呃(UTF-8) :" + " 呃呃 ".getBytes("UTF-8").length);
        System.out.println("");
        System.out.println("a(UTF-16)    :" + "a".getBytes("UTF-16").length);
        System.out.println("aa(UTF-16)   :" + "aa".getBytes("UTF-16").length);
        System.out.println(" (UTF-16)   :" + "  ".getBytes("UTF-16").length);
        System.out.println(" 呃呃(UTF-16) :" + " 呃呃 ".getBytes("UTF-16").length);
运行结果为:
a(Unicode)      :4
aa(Unicode)      :6
(Unicode)     :4
呃呃(Unicode) :6

a(UTF-8)      :1
aa(UTF-8)    :2
(UTF-8)     :3
呃呃(UTF-8) :6

a(UTF-16)      :4
aa(UTF-16)    :6
(UTF-16)     :4
呃呃(UTF-16) :6

可以看到UTF-8的情况:一个英文字符占一个字节,一个汉字占三个字节。Unicode和UTF-16的编码下,不管是英文字符还是汉字字符,都占两个字节,至于上面结果中多出来的两个字节是用来表示字节顺序的默认字节。
Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。

Unicode 编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在 Unicode 中是不存在的字符,所以不应该出现在实际传输中。 Unicode 规范建议在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。

在 Java 中直接使用Unicode 转码时会按照UTF-16LE 的方式拆分,并加上 BOM。 如果采用 UTF-16 拆分,在 Java 中默认采用带有 BOM 的 UTF-16BE 拆分。


可能大部分人对UTF-8用的比较多,通过查资料得到如下结论:

UTF-8 使用一至四个字节为每个字符编码。128 个 ASCII 字符(Unicode 范围由 U+0000 至 U+007F)只需一个字节,带有变音符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及马尔代夫语(Unicode 范围由 U+0080 至 U+07FF)需要二个字节,其他基本多文种平面(BMP)中的字符(CJK属于此类-Qieqie注)使用三个字节,其他 Unicode 辅助平面的字符使用四字节编码。


所以在java下不能使用byte[]+StringBuffer读取字符:StringBuffer是针对char操作的(String也是)。读取byte时可能刚好把一个多字节的char分成前后两批加入StringBuffer。这样就破坏了char的完整性了。而如果你使用UTF-8编码的中文,你就会中招,导致乱码(其实是因为你的读取是由于byte失去原有顺序导致的,跟一般的乱码还不一样) 。

可以用StringBuffer + bufferedReader.readLine(),读出一行行后再加入StringBuffer。

或者用stringbuffer+reader.read(char[])的形式,毕竟错误是由byte[]造成,而不是StringBuffer。


总上所述:

Unicode和UTF-16:1个字符占2个字节(不管是哪国语言)

UTF-8:1个英文字符占1个字节,一个汉字(包括日文和韩文等)占3个字节

Java中的char默认采用Unicode编码,所以Java中char占2个字节

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值