字符集:
ASCII:American Standard Code for Information Interchange,美国信息互换标准代码
一个字节,其编码范围是0x00-0x7F,共128个字符。
最高位为0,低 7 位表示128个字符,包括大小写字母、数字0-9、标点符号、非打印字符(换行符、制表符等4个)以及控制字符(退格、响铃等)组成。
ISO-8859-1(扩展字符集):对ASCII扩展,主要支持欧洲使用的语言。
一个字节,向下兼容ASCII,其编码范围是0x00-0xFF,共256个字符。
0x00-0x7F之间完全和ASCII一致,0x80-0xFF之间是扩展部分。
GB2312:信息交换用汉字编码字符集, ASCII 的中文扩展,用于中文编码。
汉字占用二个字节,字母数字占一个字节,是为了兼容ASCII(中国人也需要字母和数字)
由于ASCII最高位为0,因此GB2312 规定汉字的两个字节的最高位都是1。
第一个字节(高字节)从0xA1用到 0xF7,第二个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了,ASCII 里本来就有的数字、标点、字母也都编了两个字节长的编码,这就是常说的”全角”字符,而原来在ASCII码就叫”半角”字符了
文件长度为3个字节,前二位为中文汉字,最后一个字节为字母A。
GBK: 汉字内码扩展规范
由于GB2312编码不够用,所以出现GBK编码。GBK编码是GB2312的扩展,是向上兼容的,因此GB2312中的汉字的编码与GBK中汉字的相同。
汉字占用二个字节,字母数字占一个字节,是为了兼容ASCII(中国人也需要字母和数字)
第一个字节(高字节)从0x81用到 0xFE,第二个字节(低字节)从0x40到0xFE(不再要求低字节最高位为1),这样能表示更多的汉字,共23940个码位,共收录了21003个汉字,完全兼容GB2312-80标准,支持国际标准ISO/IEC10646-1和国家标准GB13000-1中的全部中日韩汉字,并包含了BIG5编码中的所有汉字。
ASNI编码:
不同的国家和地区制定了不同的标准,由此产生了 GB2312、GBK、Big5、Shift_JIS 等各自的编码标准。这些使用 1 至 4 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文Windows操作系统中,ANSI 编码代表 GBK 编码;在日文Windows操作系统中,ANSI 编码代表 Shift_JIS 编码。
unicode:
”Universal Multiple-Octet Coded Character Set”,简称 UCS
Unicode也是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码方案。Unicode的学名是"Universal Multiple-Octet Coded Character Set",简称为UCS。UCS可以看作是"Unicode Character Set"的缩写。
Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。
Unicode只是一个符号集,相当于字典,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。
Unicode 兼容ASCII码,前128个字符与ASCII相同。
UCS-2 unicode的第一版本,用2个字节表示所有语言文字符号,取值范围为 U+0000~U+FFFF。
UCS-4 unicode的第二版本,用4个字节表示所有语言文字符号,它的范围为 U+00000000~U+7FFFFFFF,其中 U+00000000~U+0000FFFF和UCS-2是一样的
UCS-4, UCS-2 和 ASCII是向下兼容的,只要前面补0就可以了。
Big Endian和Little Endian
一个字符编码占多个字节,有高字节和低字节,怎样的排列顺序?
Big Endian:规定高字节在前
Little Endian:规定低字节在前。
BOM:
BOM是指字节序标志(Byte Order Mark),是为了区分big还是little字节序的,通常在UTF格式文件头位置。
UTF-16 :UCS Transfer Format 16
UTF-16 用两个字节来表示 Unicode 转化格式,对应UCS-2。UTF-16 表示字符非常方便,每两个字节表示一个字符,这个在字符串操作时就大大简化了操作,这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因。
UTF-16需要在文件头上识别字节排列顺序(BOM)。
UTF-8: UCS Transfer Format 8
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,UTF-8用1到6个字节编码UNICODE字符。
UTF-16和UTF-32表示ASCII,会浪费很多字节,只有一个字节表示符号其它字节都为0x00。
UTF-8编码规则:
1)前128个字符,一个字节表示:最高位为0,低七位编码表示128个字符----》与ASCII编码相同。相比UTF-16,UTF-32节省了很多空间。
2)其它字符,用多字节表示,第一个字节高位开始,有几个1就表示该字符由几个字节组成,之后的每个字节的高二位均为10,除了以上控制位,其余位表示UNICODE码。
Unicode/UCS-4
|
bit数
|
UTF-8
|
byte数
|
备注
|
0000 ~
007F
|
0~7
|
0XXX XXXX
|
1
|
|
0080 ~
07FF
|
8~11
|
110X XXXX
10XX XXXX
|
2
|
|
0800 ~
FFFF
|
12~16
|
1110XXXX
10XX XXXX
10XX XXXX
|
3
|
基本定义范围:0~FFFF
|
1 0000 ~
1F FFFF
|
17~21
|
1111 0XXX
10XX XXXX
10XX XXXX
10XX XXXX
|
4
|
Unicode6.1定义范围:0~10 FFFF
|
java 内部使用UTF-16表示字符char,字符串String ,StringBuilder:
System.out.println(System.getProperty("file.encoding")); char asciiA ='A'; System.out.format("A.hex=%x", (short) asciiA);//显示41,自动把第一个字节的0去掉了。 System.out.println(); char zhong = '中'; System.out.format("中.hex=%x", (short) zhong);//对第二个参数(短整型)格式化为十六进制输出,0x开头 //输出4e2d System.out.println(); char zhong1 = 0x4e2d;//unicode代码数值表示"中" System.out.println("0x4e2d=" + zhong); String zhong2 = "\u4e2d";//unicode代码字符串表示 System.out.println("\\u4e2d=" + zhong);//输出"中" FileOutputStream fos = new FileOutputStream("charset.txt"); fos.write(zhong>>8); fos.write(zhong);//用字节流输出"中"字的编码,文件中显示:4E 2A fos.write(asciiA>>8); fos.write(asciiA); //用字节流输出"A"字的编码,文件中显示:00 41 fos.close(); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("charset1.txt"),"UTF-16")); bw.write(zhong); bw.write(asciiA); bw.close();输出结果:
GBK A.hex=41 中.hex=4e2d 0x4e2d=中 \u4e2d=中charset.txt文件二进制视图:
charset1.txt文件二进制视图:
在文本视图下可以显示出汉字:ucs-2 对应UTF-16
对比charst.txt文件,本文件只是多了一个UTF-16的BOM头。
charset.txt 输出代码改为如下,即与charset1一至了:
FileOutputStream fos = new FileOutputStream("charset.txt"); fos.write(0xfe);//加上UTF-16 BOM 头 高位在前 Big Endian fos.write(0xff); fos.write(zhong>>8); fos.write(zhong);//用字节流输出"中"字的编码,文件中显示:4E 2A fos.write(asciiA>>8); fos.write(asciiA); //用字节流输出"A"字的编码,文件中显示:00 41 fos.close();
JVM 中文显示过程:
从任何数据源通过指定字符集读取字符,转换为了UTF-16保存在内存中,输出时再转换为指定的字符集输出。只要在jvm内字符的utf-16格式正确,则可以正确输出任何字符集形式。
输入数据源1:java类中写中文
javac 将java源文件编译为class文件,中文以utf-8存储,jvm启动读取class文件后,中文由UTF-8-->UTF-16。 再根据程序代码指定字符集输出。
字符集转换:utf-8-->utf-16
在JAVAC编译的时候,如果没有用-encoding参数指定JAVA源程序的编码格式,则javac.exe首先获得操作系统默认采用的编码格式System.getProperty("file.encoding")(wind7下默认字符集为GBK),认为是该源文件的编码格式。然后根据该字符集
对java源程序编译,源文件中的显示定义的中文,根据字符集读取再转换为UTF-8保存到class文件。
如果编译时使用的字符集与源文件不匹配,则:
1.编译不通过
2.以不匹配的字符集读取源文件的中文就乱码了,再换为UTF-8保存到class中也是乱码。
编码时指定源文件编码:javac -encoding GBK Test.java
如果类中写的中文,输出时乱码,则该java源文件编译时指定的字符集不正确。
java class 文件中字符以UTF-8方式保存。
public class TestClass { static String x="中A"; }
编译为class后,查看十六进制:
E4 B8 AD 是“中”字的UTF-8编码 41是“A”字的UTF-8编码
输入数据源2:文件
java以字符流方式读取文件时,如果未指定字符集(如FileReader),则使用系统字符集,window下默认为GBK,linux下看系统配置。
字符集转换:默认或指定字符集-utf-16。
如果字符集与源文件不匹配,就会乱码。
java 参数:file.encoding 设置JAVA reader writer IO时默认的字符集(对应读取、写入文件、编译JAVA源文W件)。
以上为UTF-8格式文件,不指定字符集,则按默认字符集(GBK)读取,为乱码:
二种方式解决:
1.在运行时指定-Dfile.encoding=UTF-8
2.指定读取文件的字符集
BufferedReader br = new BufferedReader( new InputStreamReader(new FileInputStream("c:\\charset.txt"),"UTF-8"));
输入数据源3:数据库
java 读取数据库是通过jdbc驱动, 驱动由数据库厂商实现,在厂商需要实现ResultSet接口:
ResultSet API:
Object |
getObject(int columnIndex) 以 Java 编程语言中 Object 的形式获取此 ResultSet 对象的当前行中指定列的值。 |
String |
getString(int columnIndex) 以 Java 编程语言中 String 的形式获取此 ResultSet 对象的当前行中指定列的值。 |
如果通过ResultSet 获取出来的数据是乱码,则为驱动问题或驱动参数问题 。
jdbc驱动以指定字符集(或默认字符集)等方式读取出来的数据,为GBK格式或UTF-8格式,都可以正确的转换为jvm内部的utf-16。
字符集转换:默认或指定字符集-UTF-16。
输出到控制台:System.out
System.out 对象输出的数据,采用系统默认字符集输出。
字符集转换:utf-16 ->默认字符集
输出到文件
使用FileWriter :采用系统默认字符集。
或使用指定字符集的Writer对象。
字符集转换:utf-16 ->默认或指定字符集
输出到数据库:
字符集转换: utf-16 ->默认或指定字符集