Java乱码问题解决方法_动力节点Java学院整理

1.文件页面编码导致的乱码。

每一个文件(java,js,jsp,html等)都有其本身的编码格式,文件中的代码在一种编码中显示正常,在另外一种编码下就会显示出乱码。

在Eclipse中,每一个工程都会有编码格式(Text file encoding), 一般默认为GBK。而一个比较好的编程习惯是新建一个项目,优先把项目的编码设为UTF-8。

这样做的原因很简单,UTF-8包含全世界所有国家需要用到的字符,是国际编码,通用性强。几种常见的字符集,GBK,GB2312,UTF-8之间的关系如下:

GBK是国家标准GB2312基础上扩容后兼容GB2312的标准。GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换

2.不同字符集的字符串转换时导致的乱码。

每一个String,底层实现都是用一个byte数组存储,使用不同的字符集,存储的数组长度当然就不同。如果不使用同一种字符集进行解码,就一定会出现乱码。

例如如下代码:

Java代码

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
public class TestCharset {
  public static void main(String[] args) throws UnsupportedEncodingException {
    String strChineseString = "中文";
    String encoding = System.getProperty("file.encoding");
    System.out.println("系统默认的字符集是:" + encoding);
    System.out.println(strChineseString.getBytes(Charset.forName("GBK")).length);
    System.out.println(strChineseString.getBytes(Charset.forName("UTF-8")).length);
    System.out.println(strChineseString.getBytes().length);
  }
} 

输出结果为:

Java代码

1.系统默认的字符集是:UTF-8

2.4  
3.6  
4.6

可以看出,使用GBK和UTF-8编码,得到的byte数组长度不一样,原因就是utf-8使用3个字节来编码中文,而GBK使用2个字节来编码中文。因为我的项目默认使用UTF-8,所以使用不加参数的getBytes()得到的数组长度和使用UTF-8编码的 字符串长度一样。关于字符集的详细知识可以参考第一部分中给出的文章地址。

 JDK中关于getBytes方法的描述:

getBytes() 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。

getBytes(Charset charset) 使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。

每一个字符串底层都有自己的编码方式。不过一旦调用getByte方法后,得到的byte数组就是使用某种特定字符集编码后的数组,不需要再做多余的转换。

当得到上面的byte数组后,就可以调用String的另外一个方法来生成需要转码的String了。

测试例子如下:

Java代码

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
public class TestCharset {
  public static void main(String[] args) throws UnsupportedEncodingException {
    String strChineseString = "中文";
    byte[] byteGBK = null;
    byte[] byteUTF8 = null;
    byteGBK = strChineseString.getBytes(Charset.forName("GBK"));
    byteUTF8 = strChineseString.getBytes(Charset.forName("utf-8"));
    System.out.println(new String(byteGBK,"GBK"));
    System.out.println(new String(byteGBK,"utf-8"));
    System.out.println("**************************");
    System.out.println(new String(byteUTF8,"utf-8"));
    System.out.println(new String(byteUTF8,"GBK"));
  }
} 

输出结果为:

Java代码

1.中文  
2.����  
3.**************************  
4.中文  
5.涓枃

可以看出,使用哪种字符集编码一个String,在生成一个String的时候就必须使用相应的编码,否则就会出现乱码。
简单来讲,只有满足如下公式的String转码,才不会乱码。

Java代码

String strSource = "你想要转码的字符串";
String strSomeEncoding = "utf-8";  //例如utf-8
String strTarget = new String (strSource.getBytes(Charset.forName(strSomeEncoding)), strSomeEncoding);  

JDK中关于getBytes方法的描述:

String(byte[] bytes)  通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。

String(byte[] bytes, Charset charset)  通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。

3.Socket网络传输时导致的中文乱码。

使用Socket进行通讯的时候,传输有多种选择,可以使用PrintStream,也可以使用PrintWriter。传输英文还好,传输中文就可能出现乱码问题。网上的说法很多,经过实际测试,发现问题还在字节和字符的问题上面。

众所周知,Java中分为字节流和字符流,字符(char)是16bit的,字节(BYTE)是8bit的。PrintStrean是写入一串8bit的数据的。 PrintWriter是写入一串16bit的数据的。

String缺省是用UNICODE编码,是16bit的。因此用PrintWriter写入的字符串,跨平台性好一些,PrintStream的可能会出现字符集乱码。

可以这样理解上面的话,PrintStream是用来操作byte, PrintWriter是用来操作Unicode, PrintStream一次读8bit的话,如果遇到汉字(一个汉字占16bit),就可能会出现乱码。一般需要处理中文时用PrintWriter好了。

最后网站测试,使用PrintWriter没有出现乱码。代码如下:

Java代码

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
public class TestSocket {
  public static void main(String[] args) throws IOException {
    Socket socket = new Socket();
    DataOutputStream dos = null;
    PrintWriter pw = null;
    BufferedReader in = null;
    String responseXml = "要传输的中文";
    //..........
    dos = new DataOutputStream(socket.getOutputStream());
    pw = new PrintWriter(new OutputStreamWriter(dos)); //不带自动刷新的Writer
    pw.println(responseXml);
    pw.flush();
  }
} 

需要注意的方面是,需要使用PrintWriter的println而不是write方法,否则服务器端会读不到数据的。原因就是println会在输出的时候在字符串后面加一个换行符,而write不会。

4.JSP中显示中文的乱码。

有的时候JSP页面在显示中文的时候会有乱码,大多数情况就是字符集配置和页面编码的问题。只要保证如下的几个配置没有问题,一般就不会有乱码出现。

a.JSP页面顶端添加如下语句:

Java代码

<%@ page contentType="text/html; charset=utf-8" language="java" errorPage="" %>  

b.在HTML的head标签中添加如下语句。

Java代码

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  

c.保证JSP的页面编码与上面两个的charset相同,这点我有在文章的第一点说过。

上面的字符集可以根据需要自己灵活选择,不一定非要utf-8。不过因为utf-8对各国语言,特别是中文支持较好,所以推荐使用。我就曾经遇到过滘在GB2312编码的页面无法正常显示的问题。

5.Post和Get传递中文,后台获取乱码。

前台传递中文也分为Get和Post方法。

a.Get方法的情况:

Get方法的时候主要是URL传递中文。

如果是在js文件中,可以使用如下代码进行中文转码。

Js代码

var url ="http://www.baidu.com/s?industry=编码"
url = encodeURI(url);  

如果是在jsp文件中,则可以使用如下语句进行转码。
页面开始引入:

Java代码

<%@ page import="java.net.URLEncoder" %>

需要转码的地方使用URLEncoder进行编码:

Js代码

<a href="xxxxx.xx?industry=<%=URLEncoder.encode(" rel="external nofollow" http://www.baidu.com/s?wd=编码", "UTF-8")%>">  

无论使用哪种方法,在后台获取中文的时候都要使用如下代码:

Java代码

request.setCharacterEncoding("utf-8");
String industry = new String(
request.getParameter("industry ").getBytes("ISO8859-1"),"UTF-8");  

【注】

1.对于request,是指提交内容的编码,指定后可以通过getParameter()则直接获得正确的字符串,如果不指定,则默认使用iso8859-1编码,为了统一,需要提交指定传输编码。

2.上面代码的第二句好像和第2条中给出的公式矛盾。我也纠结了好久,最后发现ISO8859-1是一种比较老的编码,通常叫做Latin-1,属于单字节编码,正好和计算机最基础的表示单位一致,因此使用它进行转码一般也没有问题。

iso-8859-1是JAVA网络传输使用的标准字符集,而gb2312是标准中文字符集,当你作出提交表单等需要网络传输的操作的时候,就需要把 iso-8859-1转换为gb2312字符集显示,否则如果按浏览器的gb2312格式来解释iso-8859-1字符集的话,由于2者不兼容,所以会是乱码。为了省事,建议统一使用utf-8字符集。
b.POST方法的情况。

对于Post的情况就比较简单了,只需要在post的函数调用部分,制定post的header的字符集,如:

Js代码

xmlHttp.open("post", url , true);
xmlHttp.setRequestHeader("Content-Type","text/xml; charset= utf-8");
xmlHttp.send(param);  

其中param为要传递的参数。

后台部分和get方法一样,设置如下即可,注意传输和接受的字符集要统一。

6.后台向前台传递中文乱码。

在这里提供一个函数,通过这个函数来发送信息,就不会出现乱码,核心思想也是设置response流的字符集。函数代码如下:

Java代码

/**
 * @Function:writeResponse
 * @Description:ajax方式返回字符串
 * @param str:json
 * @return:true:输出成功,false:输出失败
 */
public boolean writeResponse(String str){
  boolean ret = true;
  try{
    HttpServletResponse response = ServletActionContext.getResponse();
    response.setContentType("text/html;charset=utf-8");
    PrintWriter pw = response.getWriter();
    pw.print(str);
    pw.close();
  }catch (Exception e) {
    ret = false;
    e.printStackTrace();
  }
  return ret;
}   

7.下载文件时文件名乱码。

下过下载的人都知道下载的文件容易出现乱码,原因也是没有对输出流的编码格式进行限定。

附上一段代码,用来帮你完成无乱码下载。

Java代码

HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("text/html;charset=utf-8");
response.reset();
String header = "attachment; filename=" + picName;
   header = new String(header.getBytes(), "UTF-8");
   response.setHeader("Content-disposition", header); 

核心代码就上几句,注意第二句和第三句的reset的顺序不能搞错。

reset的作用是用来清空buffer缓存的,清空请求前部的一些空白行。

以上只是做了比较简单的总结,具体乱码有的时候可能是多个情况的组合,具体问题具体分析。如果错误欢迎指正。

(0)

相关推荐

  • Java 解决读写本地文件中文乱码的问题

    Java 解决读写本地文件中文乱码的问题 前言: 在用Java程序进行读写含中文的txt文件时,经常会出现读出或写入的内容会出现乱码.原因其实很简单,就是系统的编码和程序的编码采用了不同的编码格式.通常,假如自己不修改的话,windows自身采用的编码格式是gbk(而gbk和gb2312基本上是一样的编码方式),而IDE中Encode不修改的话,默认是utf-8的编码,这就是为什么会出现乱码的原因.当在OS下手工创建并写入的txt文件(gbk),用程序直接去读(utf-8),就会乱码.为了避免可

  • JavaWeb中获取表单数据及乱码问题的解决方法

    首先使用一个用户提交界面作为举例(文本框,密码框,选择,下拉表单等),效果如下 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="t

  • java中文传值乱码问题的解决方法

    本文实例为大家分享了java中文传值乱码问题,以及解决方法,供大家参考,具体内容如下 一般编码格式设置: 1.可以经过两次编码处理,即设置字符集后,在插入前解码字符集,也是最有效的方式 设置字符集: String value=null; try { value= URLEncoder.encode(jsonObjectPar.getString("value"), "UTF-8"); } catch (UnsupportedEncodingException e)

  • Java Web实现文件下载和乱码处理方法

    文件上传和下载是web开发中常遇到的问题,这几天在做一个项目又用到了文件下载,之前也零零散散记了些笔记,今天来做一下整理.文件上传还有待进一步测试,这里先说一下文件下载. 一.文件下载处理流程 文件下载处理流程其实很清晰,即: 1.根据文件名或者文件路径定位文件,具体的策略主要根据自己的需求,总之需要系统能找到的文件全路径. 2.获取输入流,从目标文件获取输入流. 3.获取输出流,从response中获取输出流. 4.从输入流读入文件,通过输出流输出文件.这是真正的下载执行过程. 5.关闭IO流

  • Java读取properties配置文件时,出现中文乱码的解决方法

    如下所示: public static String getConfig(String key) { Properties pros = new Properties(); String value = ""; try { pros.load(new InputStreamReader(Object.class.getResourceAsStream("/properties.properties"), "UTF-8")); value = pr

  • java表单提交中文乱码的解决方法

    本文实例为大家分享了java表单提交中文乱码的解决方法,供大家参考,具体内容如下 主页index.xml <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <html> <head> <title>servlet演示</title> </head> <body> <h2&

  • Java乱码问题解决方法_动力节点Java学院整理

    1.文件页面编码导致的乱码. 每一个文件(java,js,jsp,html等)都有其本身的编码格式,文件中的代码在一种编码中显示正常,在另外一种编码下就会显示出乱码. 在Eclipse中,每一个工程都会有编码格式(Text file encoding), 一般默认为GBK.而一个比较好的编程习惯是新建一个项目,优先把项目的编码设为UTF-8. 这样做的原因很简单,UTF-8包含全世界所有国家需要用到的字符,是国际编码,通用性强.几种常见的字符集,GBK,GB2312,UTF-8之间的关系如下:

  • Java字符编码简介_动力节点Java学院整理

    1. 概述 本文主要包括以下几个方面:编码基本知识,Java,系统软件,url,工具软件等. 在下面的描述中,将以"中文"两个字为例,经查表可以知道其GB2312编码是"d6d0 cec4",Unicode编码为"4e2d 6587",UTF编码就是"e4b8ad e69687".注意,这两个字没有iso8859-1编码,但可以用iso8859-1编码来"表示". 2. 编码基本知识 最早的编码是iso88

  • Java BigDecimal详解_动力节点Java学院整理

    1.引言 借用<Effactive Java>这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的.然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合.但是,商业计算往往要求结果精确,例如银行存款数额,这时候BigDecimal就派上大用场啦. 2.BigDecimal简介 BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组

  • Java接口的作用_动力节点Java学院整理

    1. 接口是一种规范 很好,你已经知道接口是一种规范了! 下面这张图是我们生活中遇到的接口:电源插座接口. 2. 为什么需要规范呢? 因为有了接口规范: • 任何电器只有有符合规范的插头,就可以获得电力 • 任何厂家(西门子插座,TCL插座,公牛插座...)按照规范进行制作,就能进行供电 每个厂家插座的生产技术.工艺都不一样,因为接口的implementation可以不一样,但是并不影响电器的正常工作.插座的内部实现对于电器来说是完全屏蔽的. 对于软件开发同样也是类似的: • 按照接口规范进行方

  • Java数组的特性_动力节点Java学院整理

    Java中的数组是对象吗? Java和C++都是面向对象的语言.在使用这些语言的时候,我们可以直接使用标准的类库,也可以使用组合和继承等面向对象的特性构建自己的类,并且根据自己构建的类创建对象.那么,我们是不是应该考虑这样一个问题:在面向对象的语言中,数组是对象吗? 要判断数组是不是对象,那么首先明确什么是对象,也就是对象的定义.在较高的层面上,对象是根据某个类创建出来的一个实例,表示某类事物中一个具体的个体.对象具有各种属性,并且具有一些特定的行为.而在较低的层面上,站在计算机的角度,对象就是

  • Java 中HashCode作用_动力节点Java学院整理

    第1 部分 hashCode的作用 Java集合中有两类,一类是List,一类是Set他们之间的区别就在于List集合中的元素师有序的,且可以重复,而Set集合中元素是无序不可重复的.对于List好处理,但是对于Set而言我们要如何来保证元素不重复呢?通过迭代来equals()是否相等.数据量小还可以接受,当我们的数据量大的时候效率可想而知(当然我们可以利用算法进行优化).比如我们向HashSet插入1000数据,难道我们真的要迭代1000次,调用1000次equals()方法吗?hashCod

  • EL调用Java方法_动力节点Java学院整理

    简单来说,我们在一个类中的某个方法,可以使用EL进行调用,这个能被EL表达式调用的方法称之为EL函数,但是这种方式必须满足以下两点要求: ① 在EL表达式中调用的只能是Java类的静态方法 ② 这个Java类的静态方法需要在我们另外在自定义的TLD文件中描述 满足以上两点才能被EL表达式调用. 语法:  ${prefix:方法名(参数列表) } 例1:使用EL函数来实现HTML语言的过滤转义 在web工程中自定义一个HTMLFilter类,同时定义一个静态的filter方法: package c

  • URLConnection发送HTTP请求的方法_动力节点Java学院整理

    如何通过Java发送HTTP请求,通俗点讲,如何通过Java(模拟浏览器)发送HTTP请求. Java有原生的API可用于发送HTTP请求,即java.net.URL.java.net.URLConnection,这些API很好用.很常用,但不够简便: 所以,也流行有许多Java HTTP请求的framework,如,Apache的HttpClient. 目前项目主要用到Java原生的方式,所以,这里主要介绍此方式. 运用原生Java Api发送简单的Get请求.Post请求 HTTP请求粗分为

  • Java Socket编程笔记_动力节点Java学院整理

    对于即时类应用或者即时类的游戏,HTTP协议很多时候无法满足于我们的需求.这会,Socket对于我们来说就非常实用了.下面是本次学习的笔记.主要分异常类型.交互原理.Socket.ServerSocket.多线程这几个方面阐述. 异常类型 在了解Socket的内容之前,先要了解一下涉及到的一些异常类型.以下四种类型都是继承于IOException,所以很多之后直接弹出IOException即可. UnkownHostException:    主机名字或IP错误 ConnectException

  • Java 多线程并发编程_动力节点Java学院整理

    一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种资源和状态信息,包括打开的文件.子进程和信号处理. 线程:表示程序的执行流程,是CPU调度执行的基本单位:线程有自己的程序计数器.寄存器.堆栈和帧.同一进程中的线程共用相同的地址空间,同时共享进进程锁拥有的内存和其他资源. 2.Java标准库提供了进程和线程相关的API,进程主要包括表示进程的jav

随机推荐