1 乱码的根源
在计算机中所有的数据最终都必须序列化成字节序列,如果数据恰好表示就是字符,这种序列化的过程称作编码
,
反之当要读取序列化的数据,要先反序列化,对字符数据这种过程称之为解码
。
编码和解码过程有着紧密的关联,都由编码
(前述的’编码’是一个动词,这里是一个名词)决定,
一个编码(如UTF-8,GBK)就决定了一个编码过程和一个解码过程。
只有当编码过程和解码过程使用相同的编码时,字符数据才能被正确解释,否则乱码就产生了。
乱码问题的根源就在于对字符数据的编码(写入)和解码(读取)使用了不同的编码
。
为了便于说明,我们称字符数据第一次被序列化(写入或编码)时使用的编码称为初始编码
,
最后一次被序列化时使用的编码称为当前编码
。
要反序列化(读取或解码)字符数据一般来说要使用和初始编码相同的编码。
以文本文件为例,初始编码为GBK的文本文件一般只能使用GBK来解码才能读到正确的内容,
否则就会得到乱码(不正确或毫无意义的内容)。
但是也有例外,初始编码为GB2312的文本文件能够使用GBK编码来读取,这是因为GBK兼容GB2312,
类似的,初始编码为ISO-8859-1的文本文件可以使用UTF-8编码来读取,反之却不行,初始编码
为UTF-8的文本文件不能使用ISO-8859-1来读取。假设一个初始编码为GB2312的文本文件用UTF-8
编码读取,然后再使用UTF-8编码写入到同一个文件,
下次读取时无论使用GB2312编码还是使用UTF-8编码都无法回复到以前的内容。
使用与初始编码不兼容的编码先读取然后写入一般会导致初始内容遭到永久性破坏从而表现出乱码
。
这里的例外是ISO-8859-1,它是个特殊的编码,恰好有256(一个字节能够容纳的数)个字符。
对任意初始编码的文本文件,使用ISO-8859-1读取它的内容(虽然读取的内容可能表现出乱码),
然后再以ISO-8859-1写入原文件,文件内容保持不变,下次仍能以初始编码来读取文件的正确内容。
这或许是为什么JSP的许多默认编码设置成ISO-8859-1的原因。
这种乱码出现在需要多次序列化和反序列的情况下,而这在Java程序中非常常见。
为了避免乱码需要确保所有的序列化和反序列化过程使用相同的编码
,任何一个过程
使用了不正确的编码都将导致乱码,这使得乱码问题变得十分复杂,这首先要求
我们必须对程序所有的编码和解码过程都十分清楚。下面我们就要探讨常见Java程序的编码和解码过程。
2 编码和解码过程
2.1 Java独立应用程序
在考虑Java应用程序的编码和解码过程时不仅仅要考虑运行时编码和解码过程,而且要考虑编译时的编码和
解码过程。通常Java独立应用程序的第一个编码过程是将Java程序写入到一个后缀为”.java”的文本文件中,
在编译java程序时,编译器需要知道Java文件的编码,其默认使用系统平台的编码,Windows一般是“GBK”
,Linux一般是“UTF-8”,可以使用-encoding选项来指定java文件的编码。
如果编译器使用的编码和Java文件使用的编码不相同,就会造成乱码问题。
单个人使用单个平台开发时一般不会遇到这种问题,多人开发时必须统一Java源文件的编码,
我一般喜欢使用UTF-8,编译时也要指定编码,即使源文件编码与平台默认编码相同也是如此,
这样才不会依赖某个平台。使用不同的方式来编译Java程序时,它们都有自己的方式来指定
源文件的编码,javac通过”-encoding”选项,ant通过javac任务的encoding属性,maven
通过设置compiler插件的encoding元素值。值得注意的是,当指定了错误的编码时,编译
可能都会通不过。
运行时的编码和解码过程主要是对文本文件的读和写。在Java中通过下面的方式的获得一个Writer(字符写入器):
Writer writer = new
OutputStreamWriter(new
FileOutputStream("your_file_name"
), "replace_it_with_encoding"
);
当不指定文件编码时,默认编码是系统属性file.encoding的值,可以在java启动时通过”-Dfile.encoding=utf-8”来设置默认
编码为utf-8。最好在创建Writer时指定文件编码,这可以避免对平台的依赖。
通过下面的方式获得一个Reader(字符读取器):
Reader reader = new
InputStreamReader(new
FileInputStream("your_file_name"
), "replace_it_with_encoding"
);
同样不指定编码时,默认编码是系统属性file.encoding的值,创建Reader时最好显式指定编码值,这样可以避免对平台的依赖。
对于配置文件(如xml文件)我的建议是统一使用“UTF-8”编码。
一般来说这种乱码问题很容易解决,只需要指定和文件对应的编码就可以了。
一个例外是properties文件的读取,在jdk6之前,没有对属性文件指定编码的API,
Properties只有一个load(InputStream)方法,jdk6中增加一个load(Reader)方法,
这样就可以对属性文件指定编码。jdk6之前properties文件的编码必须是ISO-8859-1,
不能表示的字符只能使用Unicode转义符来表示,需要使用native2ascii工具将某种编码
的属性文件转换成属性文件所需的格式。
另一个比较常见的运行时的编码和解码过程是对数据库的读和写。这和文件的读写类似,只不过Java没有提供公开
的API来设置数据库的编码,这一般由驱动器自动检测,在MySQL中可以通过连接参数来设置数据库的编码。
2.2 Java Web应用程序
Java独立应用程序中的编码和解码过程对于Java
Web应用程序也是适用的,这里只探讨和Java
Web应用程序相关的
编码和解码过程。同对Java源文件的编译一样,我们先要讨论JSP的编译。对JSP的编译一般分为两步,首先要将
JSP文件转换成Java文件,然后再编译这个Java文件得到class文件,因此这有两个编码和解码过程,但是这个过程是
透明的(读取JSP文件和Java文件使用的编码是相同的),我们可以认为JSP编译器直接将JSP文件编译成class文件。
同样我们必须保证JSP编译器读取JSP文件使用的编码是这个JSP文件的初始编码。和Java编译器不同,JSP编译器
使用的编码是在JSP文件中指定的,例如要使JSP编译器使用UTF-8的编码来读取JSP文件,可以使用:
<%@
page
pageEncoding=
"utf-8"
%>
如果不指定页面编码,默认值为ISO-8859-1,由于上面所说的ISO-8859-1编码的特殊性,只要正确设置响应编码,
一般来说不会观察到乱码。但是在某些特殊情况下,它可能导致原本正确的JSP文件无法编译,更重要的是编译成
Java文件可能是乱码,我们可能有时需要查看这些Java文件,这会造成稍许不便,因而最好还是设置正确的JSP页面
编码。
当响应是字符数据时,这里假设是HTML内容,需要使用某种编码将它序列化成字节序列,浏览器
(或者其它的客户端)读取响应时必须使用相同的编码,否则页面可能就会显示乱码,
一般浏览器会根据响应头Content-Type的值自动检测响应的编码。为了使浏览器能够检测到
正确的编码,可以在JSP中通过如下方式设置Content-Type响应头:
<%@
page
contentType
=
"text/html;charset=utf-8"
%>
上面的代码设置响应头Content-Type的值为“text/html;charset=utf-8”,浏览器会自动使用
UTF-8编码来读取响应内容。如果浏览器自动决定的编码不正确(这是由于没有设置正确的Content-Type响应头),
主流浏览器(如IE和Firefox)都允许手动选择编码。如果在JSP中没有指定ContentType,则会根据
pageEncoding的值来设置响应编码,如果pageEncoding也没有设置,那么响应编码的值就是ISO-8859-1。
另外响应的编码的值可以在运行时调用方法response.setCharacterEncoding(“your_encoding”)来动态改变。
和响应编码对应的是请求编码。请求一般是由浏览器发送的,Firefox和IE中使用的编码是当前页面的编码,
Firefox和IE中都可以通过菜单”查看→字符编码”得到当前页面的编码,它通常就是响应编码(如果没有手工设置编码)。
为了读取到正确的内容,服务器端也必须使用同样的编码(通常是响应编码)来读取请求内容。在JSP中无法直接设置请求编码,
但是可以通过request.setCharacterEncoding(“your_encoding”)来设置。不幸的是,在Tomcat中并没有使用请求编码来解码URI,
默认使用ISO-8859-1编码,要修改URI的编码需要在tomcat的配置文件中设置。关于更多的请求编码的内容,可以参考这篇文章
。
分享到:
相关推荐
Java 乱码问题是 Java 开发中常见的问题之一,解决这个问题需要了解 Java 的编码方式、JSP 中文乱码问题、Tomcat 5.5 中文乱码问题、JDBC ODBC Bridge 的 Bug 及其解决方法、Solaris 下 Servlet 编程的中文问题及...
### Java乱码问题详解与解决方案 #### 一、问题背景 在Java开发过程中,尤其是在处理中文字符时,经常遇到字符编码不一致导致的乱码问题。由于Java默认使用Unicode编码,而在中国大陆地区,常见的字符集为GB2312...
在Java编程中,乱码问题是一个常见的困扰,尤其是在处理字符编码时。以下是一些关键的知识点,可以帮助理解和解决Java中的乱码问题。 首先,我们需要理解字符编码的基本概念。字符编码是用来表示文本的一种方式,...
在探讨“Java乱码问题”这一主题时,我们首先需要理解字符编码的基本概念以及它在Java编程中的应用。字符编码是计算机系统用来表示文本的一种方式,它将字符映射为特定的二进制数,以便于存储和传输。常见的字符编码...
Java乱码问题解决方法,java乱码怎么解决,java项目乱码,java乱码处理,
字符集基础知识是编程领域不可或缺的一部分,特别是在处理多语言和国际化问题时。本文主要围绕字符集的概念,特别是如何解决Java中的乱码问题进行了详尽的解释。...通过深入学习和实践,所有Java乱码问题都将迎刃而解。
Java开发乱码问题解决方法汇总 Java开发中乱码问题是非常常见的问题之一,而解决这些问题需要具备一定的技术知识和经验。在本文中,我们将总结一些常见的Java开发乱码问题解决方法,希望能够为读者提供帮助。 1. ...
Java 乱码问题一直是开发...总结来说,Java乱码问题需要从源头(文件编码)、编译过程、网络传输以及服务器处理等多个层面进行排查和设置。了解并掌握这些知识点,将有助于我们更好地预防和解决Java环境下的乱码问题。
当你编写代码时是不是也遇到了乱码问题 尤其是jquery post提交 来下载看看吧 你会有所收获 (个人总结 针对不同情况)
本篇文章将深入探讨Java乱码问题的解决方法,为你提供终极必杀技。 首先,我们需要了解编码的基础知识。ASCII是最早的基础字符集,包含128个字符,而Unicode则是包含了世界上大多数语言字符的编码标准,如UTF-8、...
### Java中文乱码问题详解 #### 一、中文问题的来源与背景 计算机技术发展初期,操作系统主要支持单字节的ASCII字符集。随着全球化进程加快和技术进步,为支持多种语言,尤其是双字节编码的语言(如中文),提出了...
### Java乱码问题及其解决方案 在Java开发过程中,字符编码问题常常导致中文显示为乱码。乱码问题可能出现在各种场景下,例如JSP页面、Servlet处理请求等。本篇文章将详细探讨Java乱码问题产生的原因及解决方案。 ...
Java 乱码问题一直是开发者们头疼的问题之一,它涉及到字符编码的不同阶段,包括源文件编码、编译过程、运行环境以及网络传输等多个环节。本文主要针对这些方面进行深入的探讨和总结。 首先,我们需要理解“内码”...
### Java获取乱码问题解析与解决方案 在Java应用开发过程中,字符编码问题一直是困扰开发者的一大难题,尤其是在处理HTTP请求中的中文或特殊字符时,经常会出现乱码现象。本文将详细介绍如何通过修改`server.xml`...
在Java编程中,中文乱码问题是一个常见的困扰,尤其是在处理文件读写、网络传输或数据库操作时。本文将深入探讨几种解决Java中中文乱码问题的方法,并以MyEclipse为开发环境,结合实际示例进行讲解。 1. 文件读写中...
JAVA 中文乱码问题是开发过程中常见的问题之一,解决这个问题需要了解乱码产生的原因,然后对症下药。下面我们对容易产生乱码问题的场景进行分析,并提出解决方案。 1. 以 POST 方法提交的表单数据中有中文字符 在...
"Java中文乱码问题解决" Java中文乱码问题是Java开发中常见的问题,尤其是在Web开发中,乱码问题会导致页面显示混乱,影响用户体验。解决乱码问题需要了解编码的基本原理和各种编码格式的区别。 编码的原因可以...
解决Java乱码问题通常有以下几种方法: 1. 文件读写时指定编码:使用`FileReader`和`FileWriter`时,可以通过传递`Charset`对象来指定编码。例如: ```java FileReader reader = new FileReader("file.txt", ...