`
WessonGao
  • 浏览: 28548 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

[转]关于JAVA字符编码:Unicode,ISO-8859-1,GBK,UTF-8编码及相互转换

 
阅读更多
原文地址:http://blog.csdn.net/yanjiang212/article/details/2946837

因为url传送默认编码是容器的编码,tomcat默认是iso-8859-1.所以,request.gerParameter()获得的值必须转码,除非设置tocmat的默认url编码。 

这个是涉及到字符编码的问题   一个字符在网页间传递要经过编/解码的问题 
  我来具体解释一下这个语句username=new   String(username.getBytes("ISO8859_1"),"GBK"); 
  网页本身是gb2312(也就是gbk)对数据进行解码的,那么你要将这个数据转换成ISO8859_1解码 
  的数据,一定要先将这个数据编码成gbk,然后通过getBytes()方法将其解码成ISO8859_1编码方式,那么最后得到的数据才是以ISO8859_1进行编码的数据 
1、函数介绍
在Java中,字符串用统一的Unicode编码,每个字符占用两个字节,与编码有关的两个主要函数为:
//1)将字符串用指定的编码集合解析成字节数组,完成Unicode-〉//charsetName转换
public byte[] getBytes(String charsetName) throws UnsupportedEncodingException 
//2)将字节数组以指定的编码集合构造成字符串,完成charsetName-〉Unicode转换
public String(byte[] bytes, String charsetName) throws UnsupportedEncodingException

2、Unicode与各编码之间的直接转换
下面以对中文字符串"a中文"的编码转换为例,来了解各种编码之间的转换
1)Unicode和GBK
测试结果如下,每个汉字转换为两个字节,且是可逆的,即通过字节可以转换回字符串
String-GBK〉ByteArray:/u0061/u4E2D/u6587(a中文)-〉0x61 0xD6 0xD0 0xCE 0xC4
ByteArray-GBK〉String:0x61 0xD6 0xD0 0xCE 0xC4-〉/u0061/u4E2D/u6587(a中文)

2)Unicode和UTF-8
测试结果如下,每个汉字转换为三个字节,且是可逆的,即通过字节可以转换回字符串
String-UTF-8〉ByteArray:/u0061/u4E2D/u6587(a中文)-〉0x61 0xE4 0xB8 0xAD 0xE6%0x96 0x87
ByteArray-UTF-8〉String:0x61 0xE4 0xB8 0xAD 0xE6%0x96 0x87-〉/u0061/u4E2D/u6587(a中文)

3)Unicode和ISO-8859-1
测试结果如下,当存在汉字时转换失败,非可逆,即通过字节不能再转换回字符串
String-ISO-8859-1〉ByteArray:/u0061/u4E2D/u6587(a中文)-〉0x61 0x3F 0x3F
ByteArray-ISO-8859-1〉String:0x61 0x3F 0x3F-〉/u0061/u003F/u003F(a??)

3、Unicode与各编码之间的交叉转换
在上面直接转换中,由字符串(Unicode)生成的字节数组,在构造回字符串时,使用的是正确的编码集合,如果使用的不是正确的编码集合会怎样呢?会正确构造吗?如果不能正确构造能有办法恢复吗?会信息丢失吗?
下面我们就来看看这种情况,这部分可以说明在某些情况下虽然我们最终正确显示了结果,但其间仍然进行了不正确的转换。
1)能够正确显示的中间不正确转换
我们知道String-GBK〉ByteArray-GBK〉String是正确的,但如果我们采用String-GBK〉
ByteArray-ISO-8859-1〉String呢?通过测试结果如下:
String-GBK〉ByteArray-ISO-8859-1〉String:/u0061/u4E2D/u6587(a中文)-〉0x61 0xD6 0xD0 0xCE 0xC4-〉/u0061/u00D6/u00D0/u00CE/u00C4(a????)

这时我们得到的字符串为?乱码“a????”,但是通过继续转换我们仍然可以复原回正确的字符串“a中文”,过程如下:
String-GBK〉ByteArray-ISO-8859-1〉String-ISO-8859-1〉ByteArray-GBK〉String
对应:/u0061/u4E2D/u6587(a中文)-〉0x61 0xD6 0xD0 0xCE 0xC4-〉/u0061/u00D6/u00D0/u00CE/u00C4(a????)-〉0x61 0xD6 0xD0 0xCE 0xC4-〉/u0061/u4E2D/u6587(a中文)

也就是我们在首次构造字符串时,我们用了错误的编码集合得到了错误的乱码,但是我们通过错上加错,再用错误的编码集合获取字节数组,然后再用正确的编码集合构造,就又恢复了正确的字符串。这时就属于是“能够正确显示的中间不正确转换”。在Jsp页面提交数据处理时常常发生这种情况。
此外能够正确显示的中间不正确转换还有:
String-UTF-8〉ByteArray-ISO-8859-1〉String-ISO-8859-1〉ByteArray-UTF-8〉String


String-UTF-8〉ByteArray-GBK〉String-GBK〉ByteArray-UTF-8〉String
对应:/u0061/u4E2D/u6587(a中文)-〉0x61 0xE4 0xB8 0xAD 0xE6%0x96 0x87-〉/u0061/u6D93/uE15F/u6783(a涓枃)-〉0x61 0xE4 0xB8 0xAD 0xE6%0x96 0x87-〉/u0061/u4E2D/u6587(a中文)

4、编码过程中错误诊断参考
1)一个汉字对应一个问号
在通过ISO-8859-1从字符串获取字节数组时,由于一个Unicode转换成一个byte,当遇到不认识的Unicode时,转换为0x3F,这样无论用哪种编码构造时都会产生一个?乱码。
2)一个汉字对应两个问号
在通过GBK从字符串获取字节数组时,由于一个Unicode转换成两个byte,如果此时用ISO-8859-1或用UTF-8构造字符串就会出现两个问号。
若是通过ISO-8859-1构造可以再通过上面所说的错上加错恢复(即再通过从ISO-8859-1解析,用GBK构造);
若是通过UTF-8构造则会产生Unicode字符"/uFFFD",不能恢复,若再通过String-UTF-8〉ByteArray-GBK〉String,则会出现杂码,如a锟斤拷锟斤拷
3)一个汉字对应三个问号
在通过UTF-8从字符串获取字节数组时,由于一个


    这是java字符串处理的一个标准函数,其作用是将字符串所表示的字符按照charset编码,并以字节方式表示。注意字符串在java内存中总是按unicode编码存储的。比如"中文",正常情况下(即没有错误的时候)存储为"4e2d 6587",如果charset为"gbk",则被编码为"d6d0 cec4",然后返回字节"d6 d0 ce c4".如果charset为"utf8"则最后是"e4 b8 ad e6 96 87".如果是"iso8859-1",则由于无法编码,最后返回 "3f 3f"(两个问号)。

java   .class类的编码为:unicode;

windows 默认的编码为:中文:gb2312; 英文:iso8859;

String str = "张三" ;

byte[] jiema= str.getBytes("gb2312") ; //解码

String   bianma = new String(jiema,"UTF-8");//编码 如果上面的解码不对 可能出现问题

2. new String(charset)

    这是java字符串处理的另一个标准函数,和上一个函数的作用相反,将字节数组按照charset编码进行组合识别,最后转换为unicode存储。参考上述getBytes的例子,"gbk" 和"utf8"都可以得出正确的结果"4e2d 6587",但iso8859-1最后变成了"003f 003f"(两个问号)。

    因为utf8可以用来表示/编码所有字符,所以new String( str.getBytes( "utf8" ), "utf8" ) === str,即完全可逆。

3. setCharacterEncoding()

    该函数用来设置http请求或者相应的编码。

    对于request,是指提交内容的编码,指定后可以通过getParameter()则直接获得正确的字符串,如果不指定,则默认使用iso8859-1编码,需要进一步处理。参见下述"表单输入".值得注意的是在执行setCharacterEncoding()之前,不能执行任何getParameter()。java doc上说明:This method must be called prior to reading request parameters or reading input using getReader()。而且,该指定只对POST方法有效,对GET方法无效。分析原因,应该是在执行第一个getParameter()的时候,java将会按照编码分析所有的提交内容,而后续的getParameter()不再进行分析,所以setCharacterEncoding()无效。而对于GET方法提交表单是,提交的内容在URL中,一开始就已经按照编码分析所有的提交内容,setCharacterEncoding()自然就无效。

    对于response,则是指定输出内容的编码,同时,该设置会传递给浏览器,告诉浏览器输出内容所采用的编码。

4. 处理过程

    下面分析两个有代表性的例子,说明java对编码有关问题的处理方法。

   4.1. 表单输入

    User input *(gbk:d6d0 cec4) browser *(gbk:d6d0 cec4) web server iso8859-1(00d6 00d 000ce 00c4) class,需要在class中进行处理:getbytes("iso8859-1")为d6 d0 ce c4,new String("gbk")为d6d0 cec4,内存中以unicode编码则为4e2d 6587.

    l 用户输入的编码方式和页面指定的编码有关,也和用户的操作系统有关,所以是不确定的,上例以gbk为例。

    l 从browser到web server,可以在表单中指定提交内容时使用的字符集,否则会使用页面指定的编码。而如果在url中直接用?的方式输入参数,则其编码往往是操作系统本身的编码,因为这时和页面无关。上述仍旧以gbk编码为例。

    l Web server接收到的是字节流,默认时(getParameter)会以iso8859-1编码处理之,结果是不正确的,所以需要进行处理。但如果预先设置了编码(通过request. setCharacterEncoding ()),则能够直接获取到正确的结果。

    l 在页面中指定编码是个好习惯,否则可能失去控制,无法指定正确的编码。

    4.2. 文件编译

    假设文件是gbk编码保存的,而编译有两种编码选择:gbk或者iso8859-1,前者是中文windows的默认编码,后者是linux的默认编码,当然也可以在编译时指定编码。

    Jsp *(gbk:d6d0 cec4) java file *(gbk:d6d0 cec4) compiler read uincode(gbk: 4e2d 6587; iso8859-1: 00d6 00d 000ce 00c4) compiler write utf(gbk: e4b8ad e69687; iso8859-1: *) compiled file unicode(gbk: 4e2d 6587; iso8859-1: 00d6 00d 000ce 00c4) class.所以用gbk编码保存,而用iso8859-1编译的结果是不正确的。

    class unicode(4e2d 6587) system.out / jsp.out gbk(d6d0 cec4) os console / browser.

    l 文件可以以多种编码方式保存,中文windows下,默认为ansi/gbk.

    l 编译器读取文件时,需要得到文件的编码,如果未指定,则使用系统默认编码。一般class文件,是以系统默认编码保存的,所以编译不会出问题,但对于jsp文件,如果在中文windows下编辑保存,而部署在英文linux下运行/编译,则会出现问题。所以需要在jsp文件中用pageEncoding指定编码。

    l Java编译的时候会转换成统一的unicode编码处理,最后保存的时候再转换为utf编码。

    l 当系统输出字符的时候,会按指定编码输出,对于中文windows下,System.out将使用gbk编码,而对于response(浏览器),则使用jsp文件头指定的contentType,或者可以直接为response指定编码。同时,会告诉browser网页的编码。如果未指定,则会使用iso8859-1编码。对于中文,应该为browser指定输出字符串的编码。

    l browser显示网页的时候,首先使用response中指定的编码(jsp文件头指定的contentType最终也反映在response上),如果未指定,则会使用网页中meta项指定中的contentType.

5. 几处设置

    对于web应用程序,和编码有关的设置或者函数如下。

    5.1. jsp编译

    指定文件的存储编码,很明显,该设置应该置于文件的开头。例如:。另外,对于一般class文件,可以在编译的时候指定编码。

    5.2. jsp输出

    指定文件输出到browser是使用的编码,该设置也应该置于文件的开头。例如:。该设置和response.setCharacterEncoding("GBK")等效。

    5.3. meta设置

    指定网页使用的编码,该设置对静态网页尤其有作用。因为静态网页无法采用jsp的设置,而且也无法执行response.setCharacterEncoding()。例如:

    如果同时采用了jsp输出和meta设置两种编码指定方式,则jsp指定的优先。因为jsp指定的直接体现在response中。

    需要注意的是,apache有一个设置可以给无编码指定的网页指定编码,该指定等同于jsp的编码指定方式,所以会覆盖静态网页中的meta指定。所以有人建议关闭该设置。

   5.4. form设置

    当浏览器提交表单的时候,可以指定相应的编码。例如:。一般不必不使用该设置,浏览器会直接使用网页的编码。
分享到:
评论

相关推荐

    JAVA字符编码:Unicode,ISO-8859-1,GBK,UTF-8编码及相互转换

    ### JAVA字符编码详解:Unicode, ISO-8859-1, GBK, UTF-8 及其相互转换 #### 一、引言 在Java编程中,字符编码的管理和转换是一项基本而又重要的任务。不同的编码标准适用于不同的场景,而理解和掌握这些编码之间...

    关于JAVA字符编码:Unicode,ISO-8859-1,GBK,UTF-8编码及相互转换

    ### 关于JAVA字符编码:Unicode, ISO-8859-1, GBK, UTF-8 编码及相互转换 在Java开发过程中,字符编码是处理文本数据的基础,不同的编码方式会影响数据的存储、传输以及显示。本文将详细介绍几种常见的字符编码...

    java 编码 UTF-8、ISO-8859-1、GBK

    UTF-8、ISO-8859-1 和 GBK 是三种常见的字符编码格式,每种都有其特定的应用场景和优缺点。 首先,UTF-8 是一种广泛使用的多字节编码,能够表示几乎所有的Unicode字符,包括中文。在Java中,UTF-8 支持国际化,是...

    GBK GB2312 UTF-8 ISO-8859-1区别

    字符编码标准之GBK、GB2312、UTF-8和ISO-8859-1的比较 字符编码标准是计算机领域中的一项基本技术,用于将文字或符号转换为计算机能够识别的二进制代码。常见的字符编码标准有GBK、GB2312、UTF-8和ISO-8859-1等,...

    各种字符集编码表,包括iso-8859-1,gbk,gb18030, unicode

    本文将深入探讨四种常见的字符集编码:ISO-8859-1、GBK、GB18030以及Unicode,并结合Java国际化的字符集转换进行详细说明。 1. ISO-8859-1:这是一种西欧字符编码,包含拉丁字母、数字、标点符号和一些特殊字符。它...

    乱码 编码方式解决 gbk ISO8859-1 utf8 编码

    3. **UTF-8编码**:UTF-8是一种可变长度的Unicode编码方式,支持世界上几乎所有语言的文字,包括中文。UTF-8的最大特点是兼容ASCII,且对于英文字符只需要一个字节,因此在网络传输中非常高效。 #### 二、乱码问题...

    java编码格式转换

    - 解决方法:先将UTF-8编码的字节流转换为Unicode,然后再从Unicode转换为GBK。 - 示例:`String s = "中文"; byte[] utf8s = s.getBytes("UTF-8"); String uni = new String(utf8s, "UTF-8"); byte[] gbks = uni....

    java字符串的各种编码转换

    - **定义**:ISO-8859-1是一种8位的字符编码标准,也称为Latin-1,主要用于表示西欧语言。 - **特点**: - 支持更多的字符集(256个字符),包括西欧国家的语言字符。 - 兼容ASCII字符集。 - **示例代码**: ```...

    ISO-8859.docx

    ISO-8859-1和UTF-8是两种常见的字符编码标准。ISO-8859-1是一种单字节编码,覆盖了大部分西欧语言的字符,但它不支持中文或其他多字节字符。而UTF-8是一种变长编码,可以表示Unicode字符集中的所有字符,包括中文、...

    java字符串编码转换

    例如,将一个GBK编码的字符串转换为UTF-8编码: ```java String oldStr = "你好世界"; byte[] gbBytes = oldStr.getBytes("GBK"); String newStr = new String(gbBytes, "UTF-8"); ``` 这里的 `getBytes` 方法用于...

    Java中的字符集编码入门(五)Java代码中的字符编码转换Part1.pdf

    因为文件系统可能使用不同的编码,如GBK、ISO-8859-1或UTF-8等。Java的IO系统在此起到了关键作用,它分为面向字节的流(如InputStream和OutputStream)和面向字符的流(如Reader和Writer)。 面向字节的流处理原始...

    Java文件编码转换源码

    下面是一个简单的Java代码示例,演示如何将一个GB2312编码的文件转换为UTF-8编码: ```java import java.io.*; import java.nio.*; import java.nio.channels.*; import java.nio.charset.*; public class ...

    java字符集编码问题

    通过对ISO 8859-1、GB2312/GBK、Unicode和UTF等常见编码的理解,以及Java提供的字符串操作方法(如`getBytes`和`new String`),开发者可以有效地解决实际项目中的字符编码问题,确保应用程序能够正确地处理各种文本...

    Java字符编码及获取文件编码

    首先,我们了解基本的字符编码体系,如ASCII、ISO-8859-1和Unicode。ASCII是最基础的7位编码,可表示128个不同的字符,主要针对英语字符。ISO-8859-1是8位编码,支持更多的西欧字符。而Unicode则是一个广泛采用的...

    转换为GB2312.bat转换为UTF8.bat

    此外,对于开发者而言,了解字符编码的概念,例如ASCII、ISO-8859-1、GBK、GB18030、UTF-8等,以及它们之间的关系和转换方法,是编程基础的一部分,尤其是在处理国际化和本地化项目时。编码转换不仅限于批处理脚本,...

    JAVA字符编码系列三[借鉴].pdf

    - UTF-8是变长编码,兼容ISO8859-1,可表示Unicode字符,英文字母用1字节,汉字通常用3字节。 2. **Java中的字符处理** - `getBytes(charset)`方法用于将字符串按照指定字符集转换为字节数组,这是处理编码的关键...

    java编码转换介绍文档

    这是因为Java本身默认使用Unicode作为其内部字符编码,而操作系统或其他文件可能使用GBK、GB2312或UTF-8等不同的编码。通过转换编码,我们可以确保Java程序能够正确读取和处理这些文件。 2. 获取和使用`native2...

    JAVA及相关字符集编码问题

    例如,将一个字符串从GBK编码转换为UTF-8编码时,可以先使用`getBytes("GBK")`将字符串转换为GBK编码的字节数组,然后再使用`new String(byte[], "UTF-8")`将字节数组转换为UTF-8编码的字符串。 2. `new String...

    字符集编码

    通过对ISO 8859-1、GB2312/GBK、Unicode和UTF等编码方式的理解,可以有效避免字符编码问题导致的数据传输错误和显示乱码等问题。特别是在Java Web开发中,合理利用Java提供的字符处理API,如`getBytes(charset)`和`...

    java字符编码错误整理大全

    ### Java字符编码错误整理大全 #### 一、概述 在Java开发过程中,字符编码问题是非常常见且容易引发一系列乱码问题的重要因素。本篇将详细梳理Java中的字符编码相关知识点,帮助开发者解决实际工作中遇到的各种...

Global site tag (gtag.js) - Google Analytics