前端显示最后一个汉字出现乱码(奇数个乱码,偶数个正常)

最近在学习Java并发的时候,《Java并发编程的艺术》上第四章中有个基于线程池的简单Web服务器的例程,就照着书把代码敲了一遍。然后测试的时候发现,会有这个问题。看图。

没错,标题的最后一个汉字显示不正常,我的html:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>测试页面</title>
	</head>
	<body align="center">
		<h1>第一张图片</h1>
		<img src="1.jpg" align="center">
		<h1>第二张图片</h1>
		<img src="2.jpg" align="center" >
		<h1>第三张图片</h1>
		<img src="3.jpg" align="center" >
	</body>
</html>

很简单,但是不凑巧的是,我的标题是奇数,显示就会有问题,经过测试,如果不是奇数个汉字,在后面多加一个汉字,比如“第一张图片片”,都不会出错。

后来网上查找原因,很显然,这是字符集转换之间的问题。html无疑使用utf-8编码的,最后浏览器显示的编码也是utf-8。但是问题在于,我用于搭建服务器的IDE-eclipse默认是GBK编码的。。。。

那按常理,GBK<-->UTF-8互转应该没问题啊,但是为什么奇数有问题,偶数没问题?众所周知,汉字在GBK中的编码是三个字节,而UTF-8中汉字的编码是两个字节。诶?看出问题没有,但是,如果能够保证两者之间正常的转换也不会有问题呀。

先说说问题的解决,很简单,把eclipse的编码改成UTF-8就不会有问题了。如下图:右键java文件,选择properties,最下面Text file encoding

勾选上other,然后选UTF-8。

但是问题还是要深究一下,不然以后遇到类似的问题,也不知道怎么解决。

先看一下我写的测试代码,注释是实时的值。

public class EncoderError {
	public static void main(String[] args) throws UnsupportedEncodingException {
		String gbk = "我是谁";
		byte[] gbkGetGBKBytes = gbk.getBytes();//[-50, -46, -54, -57, -53, -83]
		byte[] gbkGetUTF8Bytes = gbk.getBytes("UTF-8");//[-26, -120, -111, -26, -104, -81, -24, -80, -127]
		String utf8 = new String(gbkGetUTF8Bytes);//鎴戞槸璋?
		byte[] utf8GetGBKBytes = utf8.getBytes();//[-26, -120, -111, -26, -104, -81, -24, -80, 63]
		byte[] utf8GetUTF8Bytes = utf8.getBytes("UTF-8");//[-23, -114, -76, -26, -120, -98, -26, -89, -72, -25, -110, -117, -17, -65, -67]
		String print = new String(utf8GetGBKBytes,"UTF-8");
		System.out.println(print);//我是??
		System.out.println(new String(gbk.getBytes("UTF-8"), "UTF-8"));//我是谁
		System.out.println(new String(new String(gbk.getBytes("UTF-8")).getBytes(), "UTF-8"));//我是??
	}
}

直接新建变量,“我是谁”,GBK编码,6个字节。gbk.getBytes()和gbk.getBytes("UTF-8")分别获得的是GBK(6个字节)和UTF-8(9个细节)编码。接下来注意了,

String utf8 = new String(gbkGetUTF8Bytes);//鎴戞槸璋?

这句,很奇葩,直接用UTF-8的编码,new字符串(用文件默认的GBK编码),这很显然出现乱码:“鎴戞槸璋?”。此时gbkGetUTF8Bytes数组中存了9个字节,在构造GBK编码的字符串的时候,会两个两个字节的构造,直到第九个字节,发现少了一个,这时候处理方法是,舍弃最后一个,也就是-127这个字节,然后就上‘?’字符的编码,也就是63。这时候,从UTF-8的角度讲,这个字符串的编码已经变了。从[-26, -120, -111, -26, -104, -81, -24, -80, -127]变成了[-26, -120, -111, -26, -104, -81, -24, -80, 63],然后我们用下面语句重新按照UTF-8编码,打印字符串

byte[] utf8GetGBKBytes = utf8.getBytes();
String print = new String(utf8GetGBKBytes,"UTF-8");
System.out.println(print);//我是??

就出现了乱码问题,而如果汉字数目是偶数,就不会出现第奇数个字节被舍弃,然后强行加了个63的字节上去,这样,不管GBK和UTF-8怎么变,都不会出现问题。

总结下来就是,问题出在,强行将UTF-8编码的数据用GBK编码,导致数据发生了改变,这时候再变回去UTF-8就变不回去了。

 

我们再来看一下,书中的简单Web服务器里面是如何对应上上面的过程的。

代码贴一段。这是读取index.html里面的文本并输出到http包中。

br= new BufferedReader(new FileReader(filename));
out = new PrintWriter(socket.getOutputStream());
out.println("HTTP/1.1 200 OK");
out.println("Server: Molly");
out.println("Content-Type: text/html; character=UTF-8");
out.println();
while((line = br.readLine()) != null){
	//System.out.println(line);
        out.println(line);
	}
out.flush();

index.html里面是utf-8编码的,然后被eclipse以GBK的形式读出来,然后println出去,然后浏览器收到字节数据后,以UTF-8显示出来。数据编码由utf-8 --> GBK --> utf-8.

问题就在于

while((line = br.readLine()) != null){
	System.out.println(line);
	out.println(line);
	}

line = br.readLine(),这里将UTF-8的数据强行以GBK编码,然后写出,这等同于最开始的

String utf8 = new String(gbkGetUTF8Bytes);//鎴戞槸璋?

 于是,出错了!

这就是问题所在,其实讲了这么多,问题解决很简单,不要用GBK编码即可,主要是对编码的过程有了更深刻的了解。

写的第一篇,很乱,继续学习。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值