java中的编码问题

一直在试图搞清楚java中的编码问题,也看了网上的一些文章,但还是云里雾里。直到最近看了方立勋老师的web课程,才略略明白一点。

在此记录一下自己的理解,看看自己能不能说清楚。

第一个问题:我在java代码中定义了一个字符串,它是什么编码?

字符串实质是一个char数组。那么char的编码,其实就是字符串的编码。那么char什么编码呢?为什么‘中‘字转int类型后的值是20013呢?

        char c = ‘中‘;
        System.out.println(c); // 中
        System.out.println((int) c); // 20013

引入第一个概念:Unicode编码

Unicode是一种“编码”,所谓编码就是一个编号(数字)到字符的一种映射关系,就仅仅是一种一对一的映射而已。

java的String使用的编码是Unicode。

来个简单的例子证明:

找个转码工具,将‘中‘字转为Unicode编码,结果是‘\u4e2d‘。用‘\u4e2d‘替换原来的‘中‘字。打印的结果和‘中‘字是一样的。

        char c = ‘\u4e2d‘;
        System.out.println(c); // 中
        System.out.println((int) c); // 20013

‘\u‘是什么意思?

‘\u‘的意思就是使用了Unicode编码。后面加上十六进制代码来表示Unicode字符。下面这段代码可以验证。

        Integer num = Integer.valueOf("4e2d", 16);
        System.out.println(num.intValue()); // 20013

第二个问题:编码和编码格式的区别是什么?

这部分内容来自文章 java中的编码和编码格式问题 作者:风未馨

1. Unicode是一种“编码”,所谓编码就是一个编号(数字)到字符的一种映射关系,就仅仅是一种一对一的映射而已。

2. GBK、UTF-8是一种“编码格式”,是用来序列化或存储1中提到的那个“编号(数字)”的一种“格式”。

编码和编码格式

  java的String使用的编码是Unicode,当String存在于内存中时(在代码中用string类型的引用对它进行操作时),是"只有编码而没有编码格式的",所以java程序中的任何String对象,说它是gbk还是utf-8都是错的,String在内存中不需要“编码格式”, 它只是一个Unicode的字符串而已。

  当字符串需要在网络中传输或要被写入文件时,就需要使用编码格式了。乱码问题也因此出现。

GBK和UTF-8

  GBK和UTF-8都是用来序列化或存储Unicode编码的数据的,但是分别是2种不同的格式,他们都是Unicode编码的实现方式;他们俩除了格式不一样之外,他们所关心的Unicode编码范围也不一样。

  UTF-8考虑了很多种不同国家的字符,涵盖整个unicode码表,所以其存储一个字符的编码的时候,使用的字节长度也从1字节到4字节不等;

  而GBK只考虑中文——在Unicode中的一小部分的字符的编码,所以它算好了只要2个字节就能涵盖到绝大多数常用中文(2个字节能表示6w多种字符),所以它存储一个字符的时候,所用的字节长度是固定的;

ASCII码和Unicode

  ASCII码,和Unicode编码一样,也是一种"编码"。

  ASCII码的范围比较小,一共规定了128个字符的编码。

  Unicode编码是一个很大的集合,现在的规模可以容纳100多万个符号。就像它的名字都表示的,这是一种包含所有符号的编码。

  当然也有其他的编码,没用过,我也不甚了解。

第三个问题:哪些地方会用到编码格式?

  前文中提到过一句话:当字符串需要在网络中传输或要被写入文件时,就需要使用编码格式了。

网络中传输:

对于java web开发人员,指的就是java web了。那在java web中,哪些地方需要设置编码格式呢?

先上个图(网上随便拷贝来的)。假定浏览器就是ie,WEB服务器是tomcat,页面是jsp,应用服务器用的是servlet。

1.  浏览器中打开了一个页面,这个页面映射应用服务的某个jsp。此时浏览器中的解码格式是什么呢?

浏览器的解码格式是在jsp中指定的,比如在jsp文件中经常可以看到这样两行代码。

他们分别是什么意思呢?


<!-- 这一行的意思是:这个jsp里面的内容都是使用utf-8编码(即内容会以utf-8编码后发送给浏览器) -->
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 
<!-- 这一行的意思是告诉浏览器:你解码的时候请使用utf-8解码哦 -->
<meta http-equiv="content-type" content="text/html; charset=UTF-8">

这样浏览在解析这个jsp的时候,就是使用utf-8编码来解码。

浏览器的解码格式也是可以在浏览器上设置的:

如果网页中出现了乱码,你换一种编码格式来解码,可能就不乱了。

2. response中也可以设置内容的编码格式和指定浏览器的解码格式。

开发人员应该都知道,jsp就是一个特殊一点的servlet。在servlet中, response有两个设置编码的方法,和jsp中的那两行编码配置有着完全相同的功能。

它们就是:

        // 表示response的内容会以utf-8的编码方式编码后发送给浏览器。     response.setCharacterEncoding("UTF-8");

     // 告诉浏览器,解码的时候也要使用utf-8解码哦。
        response.setContentType("text/html;charset=UTF-8");

3. 通过request对象可以指定应用服务用哪种编码格式来解码接收到的数据.

上面两种情况,都是讲servlet自己如何编码,然后告诉浏览器如何解码的。servlet也可以指定对接收到的对象使用哪种编码格式来解码。   

    // 通过这句话,可以指定用utf-8编码格式来解码浏览器传来的数据。不过只对post方式传来的数据有效。如果是get方法传来的数据,还是会以默认的iso-8859-1来解码。    request.setCharacterEncoding("UTF-8");

4. 设置tomcat服务器配置文件server.xml,指定以何种编码解码浏览器传来的参数。

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8" />

‘URIEncoding="UTF-8"‘, 这个属性的配置, 和"request.setCharacterEncoding("UTF-8");"这句代码的功能大致相同。都是指定tomcat服务器接受到收据后如何解码。

如果不指定,tomcat服务器会默认使用iso-8859-1来解码。

被写入文件:

1. 文件内容在被写入文件时是被编码了的,默认的编码格式是gb2312(可能和系统有关,简体中文系统测试,就是gb2312)。

也可以在代码中指定文件流在写入文件时用什么编码格式。比如指定用"utf-8".

Writer write = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");

2. 文件本身不同软件是有选择性的支持可以对哪些编码进行解码。

比如:

Excel支持gb2312,不支持UTF-8。

Txt记事本支持UTF-8编码。

所以有时候,我下载一个csv文件(指定内容使用utf-8编码)。会遇到这样的情况:

这个csv文件在使用excel打开的时候,中文是乱码的,如果换成txt打开,中文就正常显示了。

这个时候如果想要在excel中不乱码,就需要在代码中指定内容使用gb2312编码。

也可以通过txt的‘另存为‘,改变文本的编码格式。

3. 如何确定文件的编码呢?

我在win7(简体中文)系统中,右键->新建一个文本文档,nodepad++打开后,查看编码,可以看到编码是ANSI。

使用java代码生成一个txt文件,未明确指定编码格式,nodepad++打开后,查看编码,可以看到编码是utf-8。

做了一个小测试:

test1. 指定utf-8编码格式

        String fullPath = "D:\\test2.txt";
        File file = new File(fullPath);
        if (!file.exists()) {
            file.createNewFile();
        }
        Writer write = new OutputStreamWriter(new FileOutputStream(file),
                "utf-8");
        write.write("你好");
        write.flush();
        write.close();

生成的文件编码格式是:

test2. 指定gb2312编码格式

        String fullPath = "D:\\test2.txt";
        File file = new File(fullPath);
        if (!file.exists()) {
            file.createNewFile();
        }
        Writer write = new OutputStreamWriter(new FileOutputStream(file),
                "gb2312");
        write.write("你好");
        write.flush();
        write.close();

生成的文件编码格式是:

test3. 先使用utf-8生成文件,输出"你好",再使用gb2312,追加内容,输出"你好",结果是这样子的。

总结:

第一次使用utf-8编码格式输出你好,此时文件内容 第一个"你好" 是utf-8编码的,文件的解码方式也是utf-8.

第二次使用gb2312编码格式输出你好,此时的文件追加的内容 第二个"你好" 是gb2312编码的,文件的解码方式也变成了gb2312。

也就是说,txt文件会一直使用最后一次操作文件使用的编码格式来解码文件的内容。

所以第二次输出"你好"后,第一次输出的"你好"变成了乱码。

时间: 06-15

java中的编码问题的相关文章

关于java中的编码问题

GET方式提交的数据不会受页面编码的影响,应该都是以iso8859-1方式编码提交到后台程序,在后台java代码中可以通过 String str1=new String(name.getBytes("iso8859-1"),"UTF-8"); 的方式对字符串解码,解决乱码问题. 关于java中的编码问题,布布扣,bubuko.com

Java 中需要编码的场景

I/O 操作中存在的编码 我们知道涉及到编码的地方一般都在字符到字节或者字节到字符的转换上,而需要这种转换的场景主要是在 I/O 的时候,这个 I/O 包括磁盘 I/O 和网络 I/O,关于网络 I/O 部分在后面将主要以 Web 应用为例介绍.下图是 Java 中处理 I/O 问题的接口: Reader 类是 Java 的 I/O 中读字符的父类,而 InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁,它负责在 I/O 过程中处理读取字节到

JAVA中的编码分析

在实际编程中可以不用关注JVM中使用的是什么编码,而只需要关注自己输出需要采用的编码,JVM会根据你设置的编码正确操作. 1.String采用的是什么编码? 很多厂家根据规范实现了JVM,JVM只说明了String应该符合Unicode编码.Unicode编码只是一种编码模型,utf8,utf16,utf32都属于Unicode模型 ,具体的信息参阅http://www.cnblogs.com/YDDMAX/p/5360709.html 2.为什么JAVA中Char是两个字节? 参阅http:/

java中的编码

来源:https://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/#icomments 在计算机用使用0.1来保存数据,存储的单位是字节(8bit/8位),每字节保存的最大数字是256,只保存英文可以,但是加上汉字就需要扩展了. ASCII编码 总共有128位,用一个字节的低7位表示,0-31是控制字条换行回车删除等,32-126是可打印字符. ISO-8859-1 ISO组织在ASCII码基础上又制定了一些列标准用来扩展ASCII

Java中字符编码和字符串所占字节数 .

首 先,java中的一个char是2个字节.java采用unicode,2个字节来表示一个字符,这点与C语言中不同,C语言中采用ASCII,在大多数 系统中,一个char通常占1个字节,但是在0~127整数之间的字符映射,unicode向下兼容ASCII.而Java采用unicode来表示字符,一个中文或英文字符的unicode编码都占2个字节,但如果采用其他编码方式,一个字符占用的字节数则各不相同. 在 GB 2312 编码或 GBK 编码中,一个英文字母字符存储需要1个字节,一个汉字字符存储

Java中需要编码的场景

一.I/O 操作中存在的编码 涉及到编码的地方一般都在字符到字节或者字节到字符的转换上,而需要这种转换的场景主要是在 I/O 的时候,这个 I/O 包括磁盘 I/O 和网络 I/O,关于网络 I/O 部分在后面将主要以 Web 应用为例介绍. 下图是 Java 中处理 I/O 问题的接口:       Reader 类是 Java 的 I/O 中读字符的父类,而 InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁,它负责在 I/O 过程中处理

java基础----&gt;java中字符编码问题(一)

这里面对java中的字符编码做一个总结,毕竟在项目中会经常遇到这个问题. 文件的编码格式 一.关于中文的二进制字节问题 public static String CHARSET_TEXT = "我爱LL"; // 打印字节的16进制表示 private void printBinarys(byte[] buffer) { for (byte b : buffer) { System.out.print(Integer.toHexString(b & 0xff) + "

java中关于编码的问题(字符转换流及字符缓冲流 )

上次我们使用的是字节流,还有一种方式就是字符流,上次说过如何分辨使用哪种流,如果记事本可以读懂则使用字符流,否则使用字节流.使用字符流就需要牵扯到编码的问题,下面给出一种转化流的格式. OutputStreamWriter OutputStreamWriter(OutputStream os):默认编码,GBK OutputStreamWriter(OutputStream os,String charsetName):指定编码.InputStreamReader InputStreamRead

还是java中的编码问题

用Java,linux我最恨的是编码问题, https://stijndewitt.wordpress.com/2010/05/05/unicode-utf-8-in-eclipse-java/ 上文建议将eclipse中全部设成utf-8: 但是我学习的书的样例代码使用的是GBK编码,在eclipse中打开时就是乱码了: 重新改成GBK,又正常了: 可以先用记事本打开,然后另存为,选择utf-8编码,这样也行.