字节流和字符流在运行的过程中查码表的方式有什么不同
这个学期我们开了JSP课,让我们最头痛的一件事就是中文字符乱码的问题,虽然老师也给讲了,但是本人资质愚钝,依然没懂,希望能有学长指点一二,在这里谢谢了。问题是这个样子:
1
OutputStream out=response.getOutputStream();
out1.write("中国".getBytes());
当我用字节流向浏览器输出中文时,居然没有乱码,记得老师说过,servlet 默认指定的字符集是iso8859-1
我用的是IE浏览器,据老师讲,凡是支持中文的浏览器,都支持gb2312,那么,当我向浏览器输出汉字的话,它应该乱码才对,但是没有。我想知道为什么。
2
PrintWriter out = response.getWriter();
out.write("中国");
当我用字符流向浏览器输出中国时,它果断乱码了,我搞不明白,为什么 字节流不会乱码,而字符流就乱码了。
求大神指教,谢谢了。
[最优解释]
看看tomcat这段源码
public ServletOutputStream getOutputStream() throws IOException
{
stream = createOutputStream();///创建response的2进制的输出流
return stream;
}
public PrintWriter getWriter() throws IOException
{
ResponseStream newStream = (ResponseStream)createOutputStream();////////创建2进制流
OutputStreamWriter osr = new OutputStreamWriter(newStream, getCharacterEncoding());
writer = new ResponseWriter(osr, newStream);///得到response的字符输出流
}
public String getCharacterEncoding()//////response的编码,默认是ISO-8859-1的
{
if(encoding == null)//////////////////////////////////如果没有指定编码
{
return "ISO-8859-1";
} else
{
return encoding;
}
}
public void setContentType(String type);设置response的类型和编码
{
encoding = RequestUtil.parseCharacterEncoding(type);////////得到指定的编码
if(encoding == null)
{
encoding = "ISO-8859-1";//////////////////////////如果沒有指定编码方式
}
else
{
contentType = type + ";charset=" + encoding;
}
}
"中国" 转编码为iso_8859_1 肯定乱麻
[其他解释]
response.setContentType这个方法应该知道吧,是指定输出类型的,默认是text/html
用java.net.URLEncoder类,这个是html格式网络传输文本数据时编码用的,
text/html就会把程序里需要输出的内容利用java.net.URLEncoder解析html传输时需要的格式,
如果你是用PrintWriter去输出的话,因为你没设定字符编码格式,
所以默认编码格式是iso-8859-1,
那么服务器会用URLEncoder.encode("中国", "iso-8859-1")
就是以iso-8859-1的格式去编码字符串"中国",
然后再把编码后的字符串发送给客户端浏览器,客户段浏览器是按照自己的编码格式,
比如是gbk,那么就是URLDecoder.decode(接收的字符串, "gbk")解码,
那么自然得到的就是??
而"中国".getBytes()这个得到的是一个长度为4的byte数组,
而且是用OutputStream直接发送的,不需要经过服务器编码,直接发送给客户浏览器,
客户浏览器也不需要解码,类似于得到new String("中国".getBytes(),"gbk")这样的一个字符串,
所以用outputstream输出没有出现乱码情况。
最后,以上过程只是为了理解方便才用URLEncoder和URLDecoder,
http网络传输协议的解码和编码真实过程要复杂很多,并不是这么简单。
[其他解释]
response.getOutputStream是直接以低级流形式输出,不需要经过服务器编码,
由于java内部汉字的unicode编码是和GBK的汉字编码是一样的,
所以客户段这边能正常显示。
[其他解释]
这个不用纠结。你们以后会学到Filter过滤器。写一个类,web.xml中配置一下。整个应用都不会再乱码了。所以不用纠结这些。
乱码的原因:(去查同一张码表,没有乱码;查A表加密,查B表解密,当然得不到正确的密码了,自然乱码了。)
编码码表==解码码表,就不会乱码。
完全没必要研究这些小问题。只要知道怎么去解决乱码就行了。用过滤器就好了。
[其他解释]
3楼说的好。。。
[其他解释]
4楼说的对,但是我如果弄不明白,心里会不舒服,再碰到类似的问题心里就慌张不知所措了,还是弄明白的好。
我把上面的代码稍微改一下,
OutputStream out=response.getOutputStream();
out1.write("中国".getBytes("utf-8"));
这样改的话肯定乱码了。
我还有一点不明白就是三楼学长的这句话 :
response.getOutputStream是直接以低级流形式输出,不需要经过服务器编码,
既然低级流不需要经过服务器编码,我又指定了编码集,服务器又照做了,是不是说,服务器有个缺省的方式-对于字节流缺省编码集的情况下,服务器不会编码,如果指定了则会按指定的编码。
不知道我这样理解对不对。
[其他解释]
不是服务器默认的编码格式,而是是string.getBytes()这个应该是按照java(api里是指平台)默认的编码格式得到的字节数组
java api里面的
getBytes
public byte[] getBytes()使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
所以你getBytes这步就已经获得了指定编码的字节数组了。
[其他解释]