字符编码问题一直都是令人头痛,查阅资料,写下了《java 字符转换问题的学习笔记》。
什么是字节流与字符流的转换? 什么时候会做转换?
字符就是char类型, 是双字节的, 用unicode, 一个char就是实际上的一个字符;字节就是byte类型, 是单字节的,实际的字符串根据编码不同,用单字节或者双字节来表示。
常用的String类型核心就是char[],String.length()就是char[]数组的大小,因此当encoding没有转换错误时,String长度是字符的个数,不管是中文还是英文。做字符处理的时候也从来不会出现截断半个字符的问题。
Java内部都是用char的,但是很多时候做输入输出就要用byte stream,例如文件、数据库、网络。
当数据要从char变为byte,或者byte变成char时,就要做转换。
同样的内容,用不同的编码方式(encoding),byte stream是不同的,转换的时候需要指定使用的encoding。
JVM的file.encoding属性确定了JVM的缺省的编码/解码方式:从而影响应用中所有字节流==>字符流的解码方式 字符流==>字节流的编码方式。在不同OS平台上,这是由locale决定的,缺省encoding在中文平台为GBK,英文平台为8859_1。
Java I/O
Reader和Writer核心是char,InputStream和OutputStream核心是byte。
专门有bridge类做Reader/Writer与InputStream/OutputStream的转换:InputStreamReader/OutputStreamWriter。
UTF8与unicode
准确的说,UTF8不是unicode,它也只是一种编码方式,不过它的编码空间可以容纳unicode的所有字符。因此UTF8是一种很适合于存储unicode的外码。UTF8是变长编码,中文3字节。
什么地方会发生转换?
从数据库到java程序 byte——〉char
从java程序到数据库 char——〉byte
从文件到java程序 byte——〉char
从java程序到文件 char——〉byte
从java程序到页面显示 char——〉byte
从页面form提交数据到java程序 byte——〉char
从流到java程序 byte——〉char
从java程序到流 char——〉byte
源程序中的字符串
最早的字节流解码过程从javac的代码编译就开始了,写在源文件中的字符串是按照一定的编码方式的(如gbk),java编译器根据缺省的encoding来对源代码中的字符串做解码,在java bytecode中存储为unicode char。
数据库中的字符编码方式
数据库中的东西都是二进制存放的,支持任何数据,理论上说,与编码并没有关系。不过,如果没有指定字符集,在排序、匹配的时候有问题,接口的地方也会出现问题。
因此就涉及到以什么编码方式来保存到数据库中了。平常我们用数据库工具或者其他程序写数据库时,都是直接用系统编码方式,也就是gbk。但是,JDBC在访问数据库时,缺省是用数据库的字符集,通常为8859_1的,本来应该是gbk->unicode却变成了8859_1->unicode,就会出现乱码。连接串中加上参数可以强制jdbc按照gbk做转换。
jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=GBK
不过这样数据库还是只能支持gbk,如果写入big5码,同样会出现转换错误的问题。最佳方案还是用UTF8来编码,这样可以容纳unicode所有字符,覆盖了gbk、big5等各个字符集的范围。
MySQL原来不支持UTF8,直到目前的最新版本4.1才加入unicode支持,但目前4.1版本还在alpha阶段。
Swing的字符集问题
从目前的试验看来,swing的组件会自动根据系统encoding做转换,并不需要干预。