java中文乱码问题

       java编程的初学者几乎都遇到过中文乱码问题,乱码的形式多种多样:写入文件中的中文在再次打开后显示乱码、写入数据库中的中文在再次读取时显示乱码、在Web表单中填写的中文一旦提交到服务器端便显示乱码、在开发状态下显示正常的HTML页面或者JSP页面在用户的浏览器中中文显示乱码···

       首先明确一点,如果把上述的种种中文显示紊乱的现象一概称为中文乱码问题,这首先是一个不严谨的命题,因为导致中文乱码的原因不止一种,有的根本就不能称为技术问题。比如,不能期望没用中文字符集支持的计算机能正确显示HTML页面中包含的中文。再比如,有的场合要求字符串按照某种编码格式(如Base64、QP等)对二进制数据进行编码使之称为能被打印的字符串之后再传输,邮件采用的MIME报文便是其中的典型情况,然而数据的接受方却没有遵循约定进行反向的解码工作而导致信息无法正常显示。

       我曾经为导师的课程设计编写一个课程设计网站,用于收交作业等,使用ASP.NET+Mysql,现在许多90后的名字都很怪异,有许多含有生僻字,当导入这些名字的时候就出现问题了,数据库存储的全是?,我以为是我程序写的有问题,改了很多地方,最后发现是自己mysql设置的字符集不正确,最后统一成UTF-8就完全解决了。

     关于字符集问题,针对不同的表现形式不同和乱码的成因不同,最终适合采用的解决方法也不同。最好的解决方法表示不让问题发生,以下两点是预防字符集问题的“金科玉律”,也是解决字符集问题的基石。

  •      任何字符串都是采用了某种字符集的。不要认为没有发生乱码问题,便不存在字符集这一说法,即使是最平常的全英文字符串,也是采用了诸如ASCII这样的字符集,只是因为所有的字符集都兼容(涵盖)了英文字符集,所以英文字符串一般不会产生字符集问题。
  •       字符集问题的终极解决之道是两个字:一致。不要奢望一个已经乱码的字符串再通过转换字符集的手段将其转变回来,因为这是很危险的;也不要奢望new String(byte[] bytes,String charsetName)是万能钥匙,能让字符串在各种字符集之间任意转换。

        关于new String(byte[] bytes,String charsetName)的用法,请记住两点:

  •         从字符串获取字节数组,必须采用字符串实际采用的字符集,否则乱码问题就此产生。
  •         不能依靠该方法实现任意字符集之间的转换,比如讲一个采用GBK字符集的字符串转换为采用UTF-8,这是不现实的。该方法只能实现:
  1. 围绕ISO8859_1的转码;
  2. 在一个特定的字符集内实现字符化/反字符化,比如将一个采用不明字符集的字符串str用GBK方式获取字节数组:byte[] bytes=str.getBytes("GBK"),然后通过new String(bytes,"GBK")的方式将其字符化。一般情况下,这个字符串的底层字节序列回归原状,不至于让情况恶化。但是如果恰巧该字符串是采用三字节字符集UTF-8的,经过采用二字节字符集GBK的一轮字符化/反字符化操作,那么该字符串的底层字节序列将被破坏,乱码问题就此产生。

      总之,不能对new String(byte[],String)方法期望过高,用与字符串的实际情况一致的字符集读写字符串,才是避免乱码问题的根本。

     在上面提出的两条根本准则的基础上,继续观察字符集问题。字符集问题可以归结为三大类型。

  •        向文件中写入数据和从文件中读取数据

       在保存文件时发生了一件容易被人忽视的问题,文件中的数据被选择采用了一种字符集。比如我们在Eclipse中编辑的文本,在保存时采用的字符集便是我们在工程实行中设置的字符集。再比如我们在记事本另存文件也允许自由选择字符集。一旦文件被保存成功,就注定了以后只能用正确的字符集来读取文件内容!

       对于java程序开发人员,有一个自由选择字符集保存文件的机会:

OutputStreamWriter(OutputStream out,String charsetName);

在读取文件时,选择正确的字符集的方式如下:

BufferReader reader=new BufferReader(InputStreamReader(InputStream is,String charsetName));
String msg=reader.readLine();

浏览器在从Web服务器下载完网页文件之后也存在一个选择正确的字符集读取和显示的问题。浏览器是根据HTML文件的Content-Type这一元数据项的定义来选择字符集的,如果没有给出这一元数据项,浏览器将自能猜测字符集;如果给出了错误的元数据项值,将直接导致显示出来的信息乱码。

  • 想网络发送数据和从网络读取数据

        我们在Web页面表单上填写的汉字或者其他字符,都是采用当前HTML文件的Content-Type元数据项中的字符集来向网路提交的。但是java在网络传输过程中,一律采用ISO88591字符集,因此在从ServletRequest中读取参数值时需要用new String(str.getBytes("ISO8859_1"),"上传字符集名称")将其纠正过来。

        在Web应用系统中发生的字符集问题,其背后可能还有另一双“黑手”。那便是ServletRequest.setCharacterEncoding()和ServletResponse.setCharacterEncoding()。这两个方法是否发挥作用,视不同的Web容器而定,原则上均应该与网页的Content-Type元数据项保持一致。

  • 向数据库中写入数据和从数据库中读取数据

        在涉及数据库的场合,问题可能会进一步复杂化,因为数据库自身也存在字符集的概念。保持不变的原则是数据库字符集与写入其中的字符串的字符集保持一致,而在从数据库中读取时仍然采用这一字符集。

       总之,字符集问题尽管表现多端,但却不是一个很复杂的问题,也不值得我们花费太多时间在其中。只要对正在操作的字符串所采用的字符集做到了然于胸,就能完全能够避免;反之,在应该指定字符集的关键时刻没有指定,很多容器和框架采取的办法便是采用操作系统当前的LANG环境变量所指示的字符集——这当然是很危险的,例如DOM4J便是根据平台语言环境来组织字符串的。


               

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值