Java操作:中文乱码解决方案
来源:互联网 发布:搜图用什么软件 编辑:程序博客网 时间:2024/05/18 10:48
阅读该文之前,需要对字节、字符与编码有所了解,否则将不容易理解。可参照《字节、字符与编码》
乱码产生的原因以及解决方案
所有数据都是以流的方式进行传输与存储的,比如读取一个文件的数据,将文件数据写入到输入流中,程序从输入流中读取数据,保存数据时,程序将数据写入到输出流中,并最终将输出流中的数据写入到文件。所以不管是输出还是输入,都是使用的流,但流中其实全是以字节表示。
所以,当我们在数据的传输或存储过程中,如果没有使用正确的编码进行转换,则会出现规则值与编码规则不对应的情况 ,即一些中文或符号在该编码规则下表现成为一些奇特的符号,我们通常称之为乱码。
- 产生乱码原因一:
比如'中'字,按GB2312生成[0xD6, 0xD0] 这两个字节,通过 iso-8859-1 转化为字符串时,将直接得到 [0x00D6, 0x00D0] 两个 UNICODE 字符,即 "ÖÐ",即为我们通常所说的乱码。
代码:
byte[] bys = "中".getBytes("GB2312");
String result = new String(bys, "ISO-8859-1");
System.out.println(result);
输出结果:ÖÐ
解决方案:
使用 bytes = string.getBytes("iso-8859-1") 来进行逆向操作,得到原始的“字节串”。然后再使用正确的 ANSI 编码,比如 string = new String(bytes, "GB2312"),来得到正确的“UNICODE 字符串”。
- 产生乱码原因二:
比如:byte[] bys = "中".getBytes("ISO-8859-1");由于字符‘中’并不在编码‘ISO-8859-1’的映射规则内,故映射了一个符号‘?’,而‘?’在UNICODE中的映射值为63,故得到bys长度为1,且值为63,不论怎么转换,我们都不能将63转换成字符‘中’,这是一个不可逆的操作。
输出结果:锟斤拷锟斤拷锟斤拷锟角非碉拷失
代码:
String te = "顶起顶起是非得失 ";
String ret = new String(te.getBytes("GBK"), "UTF-8");
ret = new String(ret.getBytes("UTF-8"), "GBK");
System.out.println(ret);
解决方案:
使用正确的编码进行转换,如果在不明确编码的情况下,可先将字节流转成ISO-8859-1编码的字节流进行发送与接收,并在相应处理方进行对应编码转换。
代码:
String te = "顶起顶起是非得失 ";
String ret = new String(te.getBytes("GBK"), "ISO-8859-1");
ret = new String(ret.getBytes("ISO-8859-1"), "GBK");
System.out.println(ret);
输出结果:顶起顶起是非得失因为ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF。在其编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃。换言之,把其他任何编码的字节流当作ISO-8859-1编码看待都没有问题。
- 产生乱码原因三:
经典案例
- 文件上传或下载
BufferedInputStream inBuff = null;
BufferedOutputStream outBuff = null;
try
{
// 新建文件输入流并对它进行缓冲
inBuff = new BufferedInputStream(new FileInputStream(sourceFile));
// 新建文件输出流并对它进行缓冲
outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));
// 缓冲数组
byte[] b = new byte[5120];
int len;
while ((len = inBuff.read(b)) != -1)
{
outBuff.write(b, 0, len);
}
// 刷新此缓冲的输出流
outBuff.flush();
inBuff = new BufferedInputStream(new FileInputStream(sourceFile));
// 新建文件输出流并对它进行缓冲
outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));
// 缓冲数组
byte[] b = new byte[5120];
int len;
while ((len = inBuff.read(b)) != -1)
{
outBuff.write(b, 0, len);
}
// 刷新此缓冲的输出流
outBuff.flush();
}
finally
{
// 关闭流
if (inBuff != null)
{
if (inBuff != null)
{
try
{
inBuff.close();
}catch(Exception e){}
{
inBuff.close();
}catch(Exception e){}
}
if (outBuff != null)
{
{
try
{
outBuff.close();
}catch(Exception e){}
{
outBuff.close();
}catch(Exception e){}
}
}
- 文件拷贝或移动
- 读取文件内容并发到其它服务器
如果是读取部分内容并发送,则有如下二种情况
a)情况一:明确文件编码集,则直接使用文件编码进行文件的读写操作;
encoding="文件编码";
b)情况二:不明确文件编码集,不能盲目的使用字符编码进行转换,否则出现不可逆操作将导致乱码产生,但由于是读取文件内容,又必须得将字节转换成字符,如不指定编码,将会使用系统的默认编码,同样可能导致乱码产生,所以使用ISO-8859-1编码(目前该编码是唯一的可逆的)将字节流转换成字符流;
encoding="ISO-8859-1";
在Java中流的IO操作有二种:字节流与字符流
字节流基类:InputStream、OutputStream
字符流基类:Reader、Writer
字节流与字符流的综合:RandomAccessFile
方式一:在读取的时候就指定编码集(ISO-8859-1)
BufferedReader br = null;
StringBuffer info = new StringBuffer();
String lineSepara = System.getProperty("line.separator");
try
{
//取得命令结果的输出流
//用一个读输出流类去读
//用缓冲器读行
br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "encoding"));
String line=null;
//直到读完为止
while((line=br.readLine())!=null)
{
info.append(line).append(lineSepara);
}
}
finally
{
if(br != null)
{
try
{
br.close();
}
catch(Exception e){}
}
}
//在接收端转成指定编码
System.out.println(new String(info.toString().getBytes("ISO-8859-1"), "GBK"));
方式二:随机按行读文件,读取出来后按真实编码进行转换
RandomAccessFile access = null;
StringBuffer info = new StringBuffer();
String lineSepara = System.getProperty("line.separator");
try
{
//取得命令结果的输出流
//用一个读输出流类去读
//用缓冲器读行
access = new RandomAccessFile(filePath, "r");
String line=null;
//直到读完为止
while((line=access.readLine())!=null)
{
info.append(new String(line.getBytes("ISO-8859-1"), "encoding")).append(lineSepara);
}
}
finally
{
if(access != null)
{
try
{
access.close();
}
catch(Exception e){}
}
}
System.out.println(info.toString());
line.getBytes("ISO-8859-1")的原因:
RandomAccessFile.read()方法实际读取的内容是一个byte但返回的是一个int,所以在byte转int的时候,进行了位与以及补码操作,其实际原理与ISO-8859-1的处理原理一致,且映射关系相同,故使用ISO-8859-1就能得到原始字节流。
- 网页提交字符串
在服务器端,Web 服务器把收到的 "%D6%D0" 转化成 [0xD6, 0xD0] 两个字节,然后再根据 GB2312 编码规则得到 "中" 字。
在 Tomcat 服务器中,request.getParameter() 得到乱码时,常常是因为前面提到的“原因一”造成的。默认情况下,当提交 "%D6%D0" 给 Tomcat 服务器时,request.getParameter() 将返回 [0x00D6, 0x00D0] 两个 UNICODE 字符,而不是返回一个 "中" 字符。因此,我们需要使用 bytes = string.getBytes("iso-8859-1") 得到原始的字节串,再用 string = new String(bytes, "GB2312") 重新得到正确的字符串 "中"。
- 从数据库读取字符串
比如Mysql4.*,默认的字符编码为latin1(ISO-8859-1),如果从数据库读取字符串时得到乱码,而数据库中存放的数据又是正确的,那么往往还是因为前面提到的原因一造成的,解决的办法还是通过 string = new String(string.getBytes("iso-8859-1"), "GB2312") 的方法,重新得到原始的字节串,再重新使用正确的编码转化成字符串。
保存到数据库的时候,也需要转换后在保存。 string = new String(string.getBytes("GB2312"), "iso-8859-1")
- 非 UNICODE 程序在不同语言环境间移植时的乱码
0 0
- Java操作:中文乱码解决方案
- java中文乱码解决方案
- java中文乱码解决方案
- Java 中文乱码解决方案汇总
- java中文乱码及解决方案
- java中文乱码-经典解决方案
- java中文乱码完全解决方案
- java中文参数乱码解决方案
- struts项目中文乱码解决方案(java中文乱码解决方案)
- C#操作MySQL中文乱码的解决方案
- Linux环境java中文乱码解决方案
- JAVA中文乱码的一些解决方案!
- java中文乱码解决方案和经验
- java中文乱码解决方案和经验
- java中文乱码解决方案和经验
- 学习备忘:Java 中文乱码解决方案汇总
- Java中文乱码问题的解决方案
- 孙鑫讲Java中文乱码问题的解决方案
- 黑马程序员---集合框架
- linux下递归统计文件夹下所有的文件
- ubuntu下常用的命令
- Chukwa 0.5下载地址
- HDU1176-免费馅饼
- Java操作:中文乱码解决方案
- 数字证书与程序的关联
- 贝式刷牙法
- UVa10878 - Decode the tape
- 马年男宝宝取名怎么取
- SQL删除添加字段
- 类的定义和声明
- js document.all的用法
- 牙齿各部位名称