编码&解码

1:I/O操作

2:内存

3:数据库

4:javaWeb

下面主要介绍前面两种场景,数据库部分只要设置正确编码格式就不会有什么问题,javaWeb场景过多需要了解URL、get、POST的编码,servlet的解码,所以javaWeb场景下节LZ介绍。

I/O操作
在前面LZ就提过乱码问题无非就是转码过程中编码格式的不统一产生的,比如编码时采用UTF-8,解码采用GBK,但最根本的原因是字符到字节或者字节到字符的转换出问题了,而这中情况的转换最主要的场景就是I/O操作的时候。当然I/O操作主要包括网络I/O(也就是javaWeb)和磁盘I/O。网络I/O下节介绍。

首先我们先看I/O的编码操作。

InputStream为字节输入流的所有类的超类,Reader为读取字符流的抽象类。java读取文件的方式分为按字节流读取和按字符流读取,其中InputStream、Reader是这两种读取方式的超类。

按字节

我们一般都是使用InputStream.read()方法在数据流中读取字节(read()每次都只读取一个字节,效率非常慢,我们一般都是使用read(byte[])),然后保存在一个byte[]数组中,最后转换为String。在我们读取文件时,读取字节的编码取决于文件所使用的编码格式,而在转换为String过程中也会涉及到编码的问题,如果两者之间的编码格式不同可能会出现问题。例如存在一个问题test.txt编码格式为UTF-8,那么通过字节流读取文件时所获得的数据流编码格式就是UTF-8,而我们在转化成String过程中如果不指定编码格式,则默认使用系统编码格式(GBK)来解码操作,由于两者编码格式不一致,那么在构造String过程肯定会产生乱码,如下:

File file = new File("C:\\test.txt");InputStream input = new FileInputStream(file);StringBuffer buffer = new StringBuffer();byte[] bytes = new byte[1024];for(int n ; (n = input.read(bytes))!=-1 ; ){buffer.append(new String(bytes,0,n));}System.out.println(buffer);

输出结果:锘挎垜鏄?cm

test.txt中的内容为:我是 cm。

要想不出现乱码,在构造String过程中指定编码格式,使得编码解码时两者编码格式保持一致即可:

buffer.append(new String(bytes,0,n,"UTF-8"));

按字符

其实字符流可以看做是一种包装流,它的底层还是采用字节流来读取字节,然后它使用指定的编码方式将读取字节解码为字符。在java中Reader是读取字符流的超类。所以从底层上来看按字节读取文件和按字符读取没什么区别。在读取的时候字符读取每次是读取留个字节,字节流每次读取一个字节。

字节&字符转换

字节转换为字符一定少不了InputStreamReader。API解释如下:InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。 每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。API解释非常清楚,InputStreamReader在底层读取文件时仍然采用字节读取,读取字节后它需要根据一个指定的编码格式来解析为字符,如果没有指定编码格式则采用系统默认编码格式。

String file = "C:\\test.txt"; String charset = "UTF-8"; // 写字符换转成字节流FileOutputStream outputStream = new FileOutputStream(file); OutputStreamWriter writer = new OutputStreamWriter(outputStream, charset); try { writer.write("我是 cm"); } finally { writer.close(); } // 读取字节转换成字符FileInputStream inputStream = new FileInputStream(file); InputStreamReader reader = new InputStreamReader( inputStream, charset); StringBuffer buffer = new StringBuffer(); char[] buf = new char[64]; int count = 0; try { while ((count = reader.read(buf)) != -1) { buffer.append(buf, 0, count); } } finally { reader.close(); }System.out.println(buffer);

内存
首先我们看下面这段简单的代码

String s = "我是 cm"; byte[] bytes = s.getBytes(); String s1 = new String(bytes,"GBK"); String s2 = new String(bytes);

在这段代码中我们看到了三处编码转换过程(一次编码,两次解码)。先看String.getTytes():

public byte[] getBytes() {return StringCoding.encode(value, 0, value.length);}

内部调用StringCoding.encode()方法操作:

static byte[] encode(char[] ca, int off, int len) {String csn = Charset.defaultCharset().name();try {// use charset name encode() variant which provides caching.return encode(csn, ca, off, len);} catch (UnsupportedEncodingException x) {warnUnsupportedCharset(csn);}try {return encode("ISO-8859-1", ca, off, len);} catch (UnsupportedEncodingException x) {// If this code is hit during VM initialization, MessageUtils is// the only way we will be able to get any kind of error message.MessageUtils.err("ISO-8859-1 charset not available: "+ x.toString());// If we can not find ISO-8859-1 (a required encoding) then things// are seriously wrong with the installation.System.exit(1);return null;}}

encode(char[] paramArrayOfChar, int paramInt1, int paramInt2)方法首先调用系统的默认编码格式,如果没有指定编码格式则默认使用ISO-8859-1编码格式进行编码操作,进一步深入如下:

String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;

同样的方法可以看到new String 的构造函数内部是调用StringCoding.decode()方法:

public String(byte bytes[], int offset, int length, Charset charset) {if (charset == null)throw new NullPointerException("charset");checkBounds(bytes, offset, length);this.value =  StringCoding.decode(charset, bytes, offset, length);}

decode方法和encode对编码格式的处理是一样的。

对于以上两种情况我们只需要设置统一的编码格式一般都不会产生乱码问题。

编码&编码格式
首先先看看java编码类图

首先根据指定的chart设置ChartSet类,然后根据ChartSet创建ChartSetEncoder对象,最后再调用 CharsetEncoder.encode 对字符串进行编码,不同的编码类型都会对应到一个类中,实际的编码过程是在这些类中完成的。下面时序图展示详细的编码过程:

通过这编码的类图和时序图可以了解编码的详细过程。下面将通过一段简单的代码对ISO-8859-1、GBK、UTF-8编码

public class Test02 {public static void main(String[] args) throws UnsupportedEncodingException {String string = "我是 cm";Test02.printChart(string.toCharArray());Test02.printChart(string.getBytes("ISO-8859-1"));Test02.printChart(string.getBytes("GBK"));Test02.printChart(string.getBytes("UTF-8"));}/*** char转换为16进制*/public static void printChart(char[] chars){for(int i = 0 ; i < chars.length ; i++){System.out.print(Integer.toHexString(chars[i]) + " "); }System.out.println("");}/*** byte转换为16进制*/public static void printChart(byte[] bytes){for(int i = 0 ; i < bytes.length ; i++){String hex = Integer.toHexString(bytes[i] & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } System.out.print(hex.toUpperCase() + " "); }System.out.println("");}
}
-------------------------outPut:
6211 662f 20 63 6d
3F 3F 20 63 6D
CE D2 CA C7 20 63 6D
E6 88 91 E6 98 AF 20 63 6D

通过程序我们可以看到“我是 cm”的结果为:

char[]:6211 662f 20 63 6d

ISO-8859-1:3F 3F 20 63 6D
GBK:CE D2 CA C7 20 63 6D
UTF-8:E6 88 91 E6 98 AF 20 63 6D

图如下:

原文链接

java中文乱码解决之道(五)—–java是如何编码解码的相关推荐

  1. java中文乱码解决之道(二)—–字符编码详解:基础知识 + ASCII + GB**

    原文出处:http://cmsblogs.com/?p=1412 在上篇博文(java中文乱码解决之道(一)-–认识字符集)中,LZ简单介绍了主流的字符编码,对各种编码都是点到为止,以下LZ将详细阐述 ...

  2. [转]java中文乱码解决之道(三)-----编码详情:伟大的创想---Unicode编码

    http://www.cnblogs.com/chenssy/ java中文乱码解决之道(三)-----编码详情:伟大的创想---Unicode编码 随着计算机的发展.普及,世界各国为了适应本国的语言 ...

  3. java中文乱码解决之道(八)-----解决URL中文乱码问题

    来源:http://www.cnblogs.com/chenssy/p/4237953.html 我们主要通过两种形式提交向服务器发送请求:URL.表单.而表单形式一般都不会出现乱码问题,乱码问题主要 ...

  4. Java中文jsp页面_java中文乱码解决之道(七)—–JSP页面编码过程

    我们知道JSP页面是需要转换为servlet的,在转换过程中肯定是要进行编码的.在JSP转换为servlet过程中下面一段代码起到至关重要的作用. 在上面代码中有两个地方存在编码:pageEncodi ...

  5. java 页面编码_java中文乱码解决之道(七)-----JSP页面编码过程

    我们知道JSP页面是需要转换为servlet的,在转换过程中肯定是要进行编码的.在JSP转换为servlet过程中下面一段代码起到至关重要的作用. 在上面代码中有两个地方存在编码:pageEncodi ...

  6. java 中文乱码_好程序员Java学习路线分享如何处理中文参数

    好程序员Java学习路线分享如何处理中文参数,为什么表单中会产生中文乱码. 好程序员Java培训 产生乱码,就是因为服务器和客户端沟通的编码不一致造成的,因此解决的办法是:在客户端和服务器之间设置一个 ...

  7. java url utf 8_java中文乱码解决之道(八)—–解决URL中文乱码问题

    我们主要通过两种形式提交向服务器发送请求:URL.表单.而表单形式一般都不会出现乱码问题,乱码问题主要是在URL上面.通过前面几篇博客的介绍我们知道URL向服务器发送请求编码过程实在是实在太混乱了.不 ...

  8. MySQL导入中文乱码解决之道

    数据库中文乱码一直是烦人的问题,网上解决方法很多,但各有出入,而且有人灵有人不灵.对于MySQL,我的解决方法如下: 1)改MySQL配置: 如:D:\Program Files\MySQL\MySQ ...

  9. java转换中文乱码_java中文乱码解决之道(四)-----java编码转换过程

    前面三篇博客侧重介绍字符.编码问题,经过这三篇博客各位博友对各类字符编码有了一个初步的了解,要了解java的中文问题这是必需要了解的.可是了解这些仅仅只是一个开始,如下博客将侧重介绍java乱码是如何 ...

最新文章

  1. 考考大家的数学,计算以下计算公式的结果
  2. C语言N台服务器通信,使用socket的Linux上的C语言文件传输顺序服务器和客户端示例程序 ....
  3. kitten编程猫里的工具函数
  4. CentOS7 防火墙规则 (firewalld)
  5. 运输层课后第61题解读
  6. 如何配置数据库ODBC数据源
  7. Dart基础第1篇:Dart环境搭建、Dart开发工具
  8. HashMap的实现原理、JDK1.7和JDK1.8的对比以及死锁问题
  9. Linux安装搜狗输入法
  10. 会议会展活动管理软件可实现哪些功能
  11. 计算机机试题Excel,2009年职称计算机考试_Excel机试题-1
  12. 射频下变频器在航空航天和国防领域的应用 ——扩展传统RF监控解决方案的实用方法
  13. linux chm 阅读器,linux下最好的chm阅读器KchmViewer,安装使用/与oklular,xCHM,gnochm简单比较...
  14. 2022校园春季招聘自带内推码投递链接合集
  15. winfrom给word加水印
  16. 安卓端使用MT终端管理器crontab设置定时任务
  17. phpstorm设置 打开文件所在目录_在根目录中配置文件夹
  18. idea热部署插件JRebel激活(强烈推荐,试试就离不开了)
  19. RK3399教程:linux clk使用
  20. 三国志战略版:Daniel_S8军争地利_刘张开荒实录三-至开七

热门文章

  1. Node mysql
  2. hadoop入门小知识点
  3. 9.struts1.x中tiles框架的使用
  4. 转:26个Jquery使用小技巧(jQuery tips, tricks solutions)
  5. CString原理介绍
  6. 对Hibernate使用之愚见
  7. Linux串口应用编程
  8. 移远EC20 4G模块LTE开发板三网通模块 MQTT阿里云物联网
  9. C语言常用字符串操作函数大全详解(strstr,strtok,strrchr,strcat,strcmp,strcpy,strerror,strspn,strchr等)
  10. 操作系统:SFTP相关知识介绍