字符编码介绍及java中的应用

字符编码,就是对日常的控制符号、文字和常用符号的二进制表示。为了准确的表示如何编号,怎么生产八位字节流,Unicode Technical Report (UTR) #17提出现代编码模型的5个层次:

1.  抽象字符表:系统所支持的所有抽象字符的集合

2. 编码字符集:就是通过某种规则把抽象字符映射到编码空间的一个码位

3. 字符编码表:把码位转换成有限位长的整数值串,utf-8等。

4. 字符编码方案:把定长的整数转化为8bit

5. 传输编码语法:为了满足传输的需要,进一步处理字节流,base64就属于这一层。

字符编码也是随着计算机科学,信息科学的发展在不断发展的,从最初的标准ASCII,到后来的拓展ASCII,再到各国不同的编码,再到目前统一的unicode编码。

ASCII编码是最早1961年提出的,包含128个字符,其中95个可显示字符和33个控制字符(比如换行)。标准ASCII码使用一个字节中的7位存 储128个字符,最高位置0,ASCII 在平时的编码中只要记住一些典型的内容就可以了,比如0是48, A是65,a是97,大小写相差32。在标准ASCII之后IBM由于系统原因扩展了ASCII码,之后国际标准化组织又制定了 ISO2022 标准,它规定了在保持与 ISO646 兼容的前提下将 ASCII 字符集扩充为 8 位代码的统一方法。ISO针对不同的地区制定了不同的扩展ASCII码。

为了满足各国的需求,各国开始针对自身文字的需要制定相关的编码,这些编码大多使用两个字节来表示一个字符,这种编码被统一称为ANSI,比较有名的包括 gb2312(简体汉字编码表)、BIG5(繁体汉字编码)、GBK(gb2312扩展表)。杂乱的ANSI码之间并不能相互兼容,因为一个编码在不同的 ANSI编码中代表着不同的字符。在此环境下unicode编码产生了,他是基于把所有已知的文字、符号都纳入其中的思想建立的。

Unicode用0 ~ 0x10FFFF来映射这些字符, 一个可以存储1114112(2^20 + 2^16)个码位,unicode使用第一个字节来作为平面,目前有17个平面,平面15,16作为自定义区域预留,平面0也有一个专用 区:0xE000-0xF8FF,有6400个码位,同时平面0的0xD800-0xDFFF,共2048个码位,被称作代理区。Unicode表示效率 低下,故出现了多种对unicode编码的方式,比较有名的有utf-8,utf-16,utf-32 ,下面主要介绍下utf8与utf16。

UTF-8是以字节为单位对unicode编码的,utf-8对不同范围的码位采用不同的长度来编码:


unicode


字节码

000000 ~ 00007f 0xxxxxxx
000080 ~ 0007ff 110xxxxx 10xxxxxx
000800 ~ 007fff 1110xxxx 10xxxxxx 10xxxxxx
008000 ~ 10ffff 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

通过这种编码方式,可以保证在使用不同的字节编码,同时在解析的时候通过识别每个字节的前缀得知当前的字符是由几个字节组成的。

UTF-16是通过16位无符号数作为码元的编码方式。U+0000 ~ U+FFFF包含了常用的字符,UTF-16直接把这个范围的码位编码为对于的16位码元,对于U+10000 到 U+10FFFF的码位,编码成2个16位码元,编码方法代码如下:

    /**
     * utf-16 编码算法, 大尾端
     * @param offset 码位对于的值
     * @return
     */
    public String convertUTF16(int offset) {
        if(offset < 0x10000) {
            int vh = (offset & (0xFF << 8)) >> 8;//higt 8 bits
            int vl = (offset & 0xFF);//low 8 bits
            return Integer.toHexString(vh) + " " + Integer.toHexString(vl);
        }
        int val = offset - 0x10000;
        int vh = (val & (0x3FF << 10)) >> 10;//higt 10 bits
        int vl = (val & 0x3FF);//low 10 bits
        int ph = 0xD800;//高位代理
        int pl = 0xDC00;//地位代理
        String firstSymbol = Integer.toHexString(ph + vh);
        String secSymbol = Integer.toHexString(pl + vl);
        return firstSymbol + " " + secSymbol;
    }

对于多个字节表示,还有个问题,就是字节顺序(BIG-ENDIAN、LITTLE-ENDIAN),unicode采用bom(byte order mark)来区分,在传输流之前,先传输bom,unicode编码格式对应bom罗列如下:

utf编码方式 bom
utf-8 EF BB BF
utf-16 LE FF FE
utf-16 BE FE FF
utf-32 LE FF FE 00 00
utf-32 BE 00 00 FE FF

备注:utf-8由于其特殊的编码格式,并不需要bom来表示其字节顺序

关于java对于编码的处理,通过几个问题来阐明:

1. java的字节顺序是什么,BIG-ENDIAN or LITTLE-ENDIAN?

java是big-endian, 这个问题可以通过程序验证:

/**
     * 检查字节顺序
     * @throws UnsupportedEncodingException
     */
    public String CheckByteOrder() throws UnsupportedEncodingException {
        String a ="a";
        byte[] arr = a.getBytes("utf-16");
        if(arr[2] == 0) {//前两位为bom
            return "big-endian";
        } else if(arr[2] == 97) {
            return "little-endian";
        } else {
            return "error";
        }
    }

2. java 中character编码方式?

在JAVA平台中,char[]、String、StringBuilder和StringBuffer类中采用了UTF-16编码,BMP字符用一个char表示,增补字符使用一对char表示。

3. java 的string.getBytes()方法获取字节使用的编码方式?

如api中所示,String.getBytes()方法使用的是默认编码,而这个编码方式和平台有关,可以通过如下方式获取平台的默认编码:

Charset.defaultCharset()

最后,StringBufferInputStream方法不建议使用,因为此类是早期的java类,read方法只获取char的低8位,会带来很多问题

public synchronized int read() {
        return (pos < count) ? (buffer.charAt(pos++) & 0xFF) : -1;
    }
时间: 2024-08-28 02:23:48

字符编码介绍及java中的应用的相关文章

字符编码介绍及不同编码区别

UNICODE,GBK,UTF-8区别 简单来说,unicode,gbk和大五码就是编码的值,而utf-8,uft-16之类就是这个值的表现形式.而前面那三种编码是一兼容的,同一个汉字,那三个码值是完全不一样的.如"汉"的uncode值与gbk就是不一样的,假设uncode为a040,gbk为b030,而uft-8码,就是把那个值表现的形式.utf-8码完全只针对uncode来组织的,如果GBK要转UTF-8必须先转uncode码,再转utf-8就OK了. 详细的就见下面转的这篇文章. 谈谈Un

字符编码介绍

参考:http://www.cnblogs.com/lizhenghn/p/3690406.html GB 2312     1981年5月发布     1.GB:国标拼音首字母: 2.共收入汉字6763个和非汉字图形字符682个: GBK           1995年12月发布 1.    GBK:"国标"."扩展"拼音首字母: 2.    GBK 向下与 GB 2312 编码兼容,向上支持 ISO 10646.1 国际标准(ISO 10646.1等同于GB 1

对字符串进行简单的字符数字统计 探索java中的List功能

题目: 统计一个字符串中数字和字符串的个数,并分别进行排列,要求 1.数字,字符串可以从键盘获取. 2.储存在list 3.统计数字个数,字符串个数 4.把数字和字符串按从小到大的顺序输出 5.不能使用数组. List的用法 List包括List接口以及List接口的所有实现类.因为List接口实现了Collection接口,所以List接口拥有Collection接口提供的所有常用方法,又因为List是列表类型,所以List接口还提供了一些适合于自身的常用方法.[自行百度] List接口提供的

对上次“对字符串进行简单的字符数字统计 探索java中的List功能 ”程序,面向对象的改进

之前的随笔中的程序在思考后发现,运用了太多的static 函数,没有将面向对象的思想融入,于是做出了一下修改: 1 import java.util.ArrayList; 2 import java.util.Collections; 3 import java.util.List; 4 import java.util.Scanner; 5 6 7 public class classtest { 8 9 List<String> number=new ArrayList<String

理解Java中字符流与字节流的区别

1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个“流动的方向”,通常可以从中读入一个字节序列的对象被称为输入流:能够向其写入一个字节序列的对象被称为输出流. 2. 字节流 Java中的字节流处理的最基本单位为单个字节,它通常用来处理二进制数据.Java中最基本的两个字节流类是InputStream和OutputStream,它们分别代表了组基本的输入字节流和输出字节流.InputStre

Java 中需要编码的场景

I/O 操作中存在的编码 我们知道涉及到编码的地方一般都在字符到字节或者字节到字符的转换上,而需要这种转换的场景主要是在 I/O 的时候,这个 I/O 包括磁盘 I/O 和网络 I/O,关于网络 I/O 部分在后面将主要以 Web 应用为例介绍.下图是 Java 中处理 I/O 问题的接口: Reader 类是 Java 的 I/O 中读字符的父类,而 InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁,它负责在 I/O 过程中处理读取字节到

Java中需要编码的场景

一.I/O 操作中存在的编码 涉及到编码的地方一般都在字符到字节或者字节到字符的转换上,而需要这种转换的场景主要是在 I/O 的时候,这个 I/O 包括磁盘 I/O 和网络 I/O,关于网络 I/O 部分在后面将主要以 Web 应用为例介绍. 下图是 Java 中处理 I/O 问题的接口:       Reader 类是 Java 的 I/O 中读字符的父类,而 InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁,它负责在 I/O 过程中处理

字符编码简单介绍

1. ASCII码 ASCII (American Standard Code for Information Interchange, 美国标准信息交换代码),是基于拉丁字母的一套编码系统.主要用于显示现代英语和其它西欧语言.它是现今最通用的单字节编码系统. 单个字节能够表示256个不同的字符,只是 ASCII 仅仅使用了当中低于\x80(即最高位字节为0)的一半来表示全部的英文字符以及一些控制字符,因此 ASCII 码的实际取值范围为0x00到0x7f之间,一共128个字符. 2. 多字节字

JAVA中文字符编码问题

JAVA的中文字符乱码问题一直很让人头疼.特别是在WEB应用中.网上的分析文章和解决方案都很多,但总是针对某些特定情况的.很多次遇到乱码问 题后, 经过极为辛苦的调试和搜索资料后终于解决,满以为自己已经掌握了对付这些字符乱码怪兽的诀窍.可当过段时间,换了个应用或换了个环境,又会碰到那讨厌的火 星文,并再次无所适从.于是下决心好好整理一下中文字符编码问题,以方便自己记忆,也为其他程序员兄弟们提供一份参考. 首先要了解JAVA处理字符的原理.JAVA使用UNICODE来存储字符数据,处理字符时通常有