Java中的编码问题:接收、转码、输出

原创 2017年06月11日 00:35:04

1 常见的问题

在从网络获取数据后,在JVM中进行解析运算时,最后输出的过程中都会遇到不同的编码转码问题。本文涉及的主要有如下问题:

  • Java发送HTTP请求后,接到服务器传回数据stream(如html文本),在Console中显示中文乱码。
  • Java将获取的数据输出为本地文件,在本地打开后中文显示乱码。

2 JVM从外部获得数据后的编码问题

2.1 关键理解

  • Java或者JVM、内存都是采用Unicode进行编码,一个char占2个bytes。
  • 在接收到IO字节流、向IO输出字节流的时候,都是以Unicode为桥梁,IO输入会先转为Unicode,输出会从Unicode转为相应编码。
  • 从服务器获取的数据,如一个html网页,meta数据中如果标记采用GBK编码,那么接收的IO byte[]中就是采用相应的编码方式表示中文的。
  • 所以从外部接收的数据,想让JVM自身能正确存储、显示,实质就是先正确利用发送方的编码方式来解读bytes,存为Unicode的char stream过程。

2.2 示例

通过这个过程了解Java在接受IO数据时的转码。GBK-> Unicode->UTF-8

//有一个URLConnection
URL realUrl = new URL("http://...");
URLConnection connection = realUrl.openConnection();
connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
//建立连接
connection.connect();
//假设服务器返回的html网页中meta标签charset="GBK"
in = new BufferedReader(new InputStreamReader(
            connection.getInputStream(),
            "gbk")); //第二个参数标记用什么编码解读byte stream
String result = "";
String line;
while ((line = in.readLine()) != null) {
    result += line;
}
// 此时result在内存是以Unicode形式编码存储,而且解读正确
// 最终result中的中文可以被正常打印再终端,在打印的时候,会根据环境设置,如JVM设置以UTF-8编码输出,则会将Unicode的char stream转为UTF-8的字符串再输出到终端。
System.out.println(result);

3 JVM输出到文件的编码

3.1 关键理解

  • Java、JVM、内存中存储的char stream是以Unicode编码的,再次强调Unicode的桥梁作用。
  • 所以一串数据如果已经被正确解读为Unicode的char stream(此时console可以正常print)存储在内存中,也就和原来是什么编码无关了,输出时的主要工作是建立需求编码对应的Writer和对应编码的内容,char stream,用正确的Writer和正确的数据就能输出正确的文件。
  • 简单来说,一个String输出到文件过程,就是将Unicode的char stream转换为对应编码的char stream在输出的过程。

3.2 示例

// 通过Charset类可以查看JVM本地的编码格式,就是默认输出时的编码
System.out.println(Charset.defaultCharset());
// 建立输出流,假设要输出服务器返回的网页信息
File file = new File("C:/Users/xxx/Documents/todo/Feedback.html");
BufferedWriter bf = new BufferedWriter(new OutputStreamWriter(
        new FileOutputStream(file),
        "GBK") // 第二个参数说明了这个writer的编码方式,否则按照默认
        );
// 获取正确编码的char stream并输出
String sr = "xxxx";
String str = new String(sr.getBytes("GBK"), "GBK");
    // 第一个参数表示用GBK的方式将Unicode char stream转为用GBK编码的byte[]
    // 有了byte[]序列还需要转为char stream,第二个参数表示生成一个GBK的String,用于输出,这才是正常的。
    // 不指定会用默认的编码方式(这里是UTF-8对字节数组再编码),输出还是UTF-8,且中文乱码。

4 JVM输出到命令提示符的编码

如果正常编译运行,用cmd通过java -jar的方式运行jar包是可以正常输出的。但如果在运行前,使用CHCP 65001这样的命令来切换显示编码到UTF-8,就会发现中文显示乱码。所以还是理解,如果以默认的方式存储的String或者自己解码的String都是以Unicode存在JVM中,在输出的时候,因为系统环境是GBK的,所以会自动以GBK的形式输出。
但如果String本身有自己的指定编码方式,那么就会直接输出其对应的byte stream到目标环境中。如从网络上获取的一段用UTF-8编码的HTTP返回的json串,在指定UTF-8的Eclipse环境中调试,console中的中文会显示正常。但是如果直接做成jar包在windows的cmd中运行,由于其环境是GBK的,就会显示乱码。解决方式如2.2实例,其中修改解码方式为:

//建立连接
connection.connect();
//用utf-8的方式解读字节流
in = new BufferedReader(new InputStreamReader(
            connection.getInputStream(),
            "utf-8"));

正确存为内存的Unicode后,在cmd中的普通输出自然就正常了。

5 参考资料

为了简洁,其他内容可以看一些参考资料。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

UML2.0类关系基本概念与StarUML2操作

介绍了UML中的关系以及在StarUML2中的操作。

Excel VBA简单使用——数据缺失处理

文章包含了VBA的快速起步需要的一些知识,介绍了变量,打印调试,if end if, for next, while wend语法,完成了一个处理数据缺失的例子。...

JAVA编码(中文转码)问题总结

本章主要分析Java编码和解码的原理,以及中文转码

PHP的json_encode中文被转码的问题 在php5.2中做json_encode的时候。中文会被unicode编码, php5.3加入了options参数, 5.4以后才加入JSON_U

PHP的json_encode中文被转码的问题   在php5.2中做json_encode的时候。中文会被unicode编码, php5.3加入了options参数, 5.4以后才加...
  • samxx8
  • samxx8
  • 2014年10月15日 17:40
  • 4309

字符编码问题之手动转码并不万能

引言 相信大家在最开始接触web的时候,因为Tomcat服务器默认的URIEncoding是ISO8859-1。 应该产生过中文乱码问题,某些前辈就会告诉你,可以手动转码。 new ...

Mac Eclipse里面编码转换正常,打成Jar包以后转码成乱码问题

问题出现的背景: 我之前都是用 Windows 操作系统的,我在 windows里面搞Java 用的是 Eclipse, 由于无知浅陋,我在 eclipse 里面的项目多是以   GBK ...

JS和JAVA中常用的编码转码函数

js中escape,encodeURI,encodeURIComponent函数和unescape,decodeURI和decodeURIComponent函数的功能 1.escape方法对Strin...
  • kkdelta
  • kkdelta
  • 2013年12月17日 16:42
  • 12735

PHP处理微信中带Emoji表情的消息发送和接收(Unicode字符转码编码)

时间 2014-12-07 00:28:08 马铖的博客-MaCheng's Blog. 原文  http://blog.mc-zone.me/article/322 主题 Un...

PHP处理微信中带Emoji表情的消息发送和接收(Unicode字符转码编码)

原文   http://blog.mc-zone.me/article/322 主题 Unicode PHP 在进行微信公众号开发者接入的时候,与用户的对话互动中,涉及到的文...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java中的编码问题:接收、转码、输出
举报原因:
原因补充:

(最多只允许输入30个字)