有关编码的一些问题

起因:

写服务器端口,用xstream返回xml时,客户端用sax解析报错:org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.

说明是xml文件头,也就是第一行解析有问题。

这里说下xstream的使用,选择SaxDriver时,会自动生成<?xml version="1.0"?>,加不了encoding属性,用DomDriver时,输出的只有xml主体,不包括xml头,头需要自己拼接

选择Dom4jDriver时,自动生成<?xml version="1.0" encoding="UTF-8"?>

不过要注意,这里的encoding是给浏览器看的,告诉浏览器用什么编码进行解析服务器或者本地传来的数据,并显示在浏览器上,对文件的保存格式什么的并没有任何作用。

客户端解析出现问题,百度说是BOM或是编码的问题,通过测试,用winhex查看,发现服务器传来的数据并没有BOM,所以就是编码问题了。服务器那边用PrintWrite以utf-8的

形式写回xml,而发现客户端这边是直接使用字节流来解析流的,所以就报错了,解决方法:

InputSource isrc = new InputSource(new InputStreamReader(is,"utf-8"));

将字节流转换为以utf-8编码读取的字符流,问题解决。

深入研究:

理解编码,一种图形或者说字符,对应一个数字,数字用十六进制表示,不同的编码,这个数字的值和所占空间大小也不同,而把一个文件存放在磁盘上的时候,

是将字符进行某种编码,形成一系列十六进制,然后将这些十六进制(准确的来说是二进制,这里为了方便,就说十六进制了)存放在磁盘上。

而所谓的那些编辑器,记事本什么的,不过是用文件保存的编码去读取那个文件,然后将对应的图形或者说字符显示出来,所以如果你的文件是以utf-8存放,一些汉字

占3个字节,兼容ascii编码,即包括了ascii的那127个字符,用同样的映射方法,具体utf-8的编码自行百度,而这时候如果设置编辑器以gbk的编码读取这个文件的话,

就会出现中文乱码,因为gbk是每2个字节读取的,也就把原来表示一个汉子的3个字节拆开了,所以很明显会出现乱码


上图是用utf-8格式读取utf-8保存的文件,三个字节对应一个汉子,在图像上可以看到最后一个字节对应的是一个空格


而当我们用gbk读取上面的相同的内容的时候,就会出现乱码

总结:文件存放虽然是存放的十六进制,但是这些十六进制是通过把某种图形或者说字符通过某种编码映射而来的,所以要想从这个文件中读取原来的内容,必须使用

相同的编码,或兼容的编码进行读取,才能还原出图像或者说字符,所以文件必有存储的编码,读取时也一定有读取使用的编码,之所以平常我们很少指定,是因为系统,

或者说软件自动帮我们设定了,但是在很多情况下,系统或者软件使用了错误的编码进行读取,那么就会出现乱码,所以很多情况下,我们得设置文件是什么编码存放,

并设置文件以什么编码读取。

java中的字节流与字符流:

现在再来理解java中字节流和字符流的区别就很简单了,对于字节流和字符流,实际上只是读取文件的方式,而真正影响乱码的情况是编码方式不一致,字节流就是一个字节一个字节的读到内存,可以说涉及不到编码,也可以说是按ascii编码一个字节对应一个字符,存放在内存中,写回文件的时候又将这个字符按照ascii编码写成相应的十六进制,然后就形成了文件,所以对于那些图片,音频什么的,就只能通过字节流来读写,因为字节流只能一个个字节的进行编码,所以也就不能对unicode

码进行读取了,读出来的肯定是乱码,但是还是一个个字节的写回文件,文件并没有损坏,用相应的编码打开还是能看到正确的内容,所以说字节流能够传输任何文件,

只是传输的过程中你有可能看不到正确的显示,但是写回文件后,用正确的方式打开是一定没问题的。

而字符流其实是对字节流进行缓冲处理,读取的时候可以设置字符流以正确编码(也就是这个文件存放使用的编码)进行读取,然后读到内存显示的就是正确的内容,

然后写回文件的时候就可以指定任意编码了,也就是文件保存的编码,保存后,再用这个编码打开文件就能够看到正确的内容了。

重要区别:

字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的

字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,

说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容

java中文字符编码问题详解:

参考文章:

JAVA中文字符编码问题详解

这篇文章讲得很详细,很值得看一看

关于编码之间转换的问题:

假设GBK保存的文件,用GBK读到内存,内存是正确的字符,这时候如果将内存中的正确字符以utf-8编码写回

文件,也就是将内存中正确的字符映射成相应的十六进制存放在磁盘上,也就是这个文件以utf-8的形式保存了,

这也是编辑器以不同格式保存文件的原理

对于一个jpg保存的图片也是一样,先通过jpg的编码将图像文件映射成一个个像素点,存放在内存中相应的数据结构

中,也就是说在内存中显示的是正确的内容,然后写回文件时,按照另一种编码,不如jpeg的编码,映射成相应的

十六进制保存在文件中,这时候这个图片格式就从jpg转换为jpeg了,下次打开,以jpg打开就显示不出来图片或者

说不能正确显示,以jpeg格式打开就能够正确显示

所以说分析编码的时候要时刻记得原本文件是什么编码存放的,然后是用什么编码读取的,最后是以什么编码保存的

思考问题:

一个GBK保存的文件,以utf-8的编码读取,读到内存明显不能够显示正确的字符,但是这时候直接又以utf-8的编码

写回文件,会发现文件的内容和以前一样(十六进制数据一模一样),但这时候文件的标记是以utf-8的形式保存的,

所以直接双击文件会出现乱码,而右键选择以gbk编码打开却能够看到正确的内容(话说这算一种加密方式么,呵呵),

也就是在内存中的是正确的字符,内存中正确就好办了,这时候你就可以用任何编码保存了,比如说我们用utf-8的

编码保存,那么就会将相应的字符安装utf-8映射成相应的十六进制存放在文件中,也就是说这个文件是utf-8保存的

文件了,这时候这个文件就可以直接打开,而且不会出现乱码了。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值