在中文环境下编程,难免会遇到乱码问题,这是因为不同的条件下对于编码的要求不相同,所以如果在我们的程序中,对于同一段信息使用的字符集(charset)不同,那信息中的中文就会变成乱码。
常见的乱码有三种,一是全问号,像"??????";二是特殊符号加一奇怪的繁体字,像"!_灑";第三种是包含了很多百分号和字母,像"A%KT%%F",这种情况其实不算乱码,只是还没有经过解码的字符串,下面我们还会提到。
因为项目的原因,我有幸在半个月的时间里接触到了几种不同情况下的乱码,花费了不少的时间和精力来解决,这里就把他们总结一下,希望能对遇到相似问题的朋友提供一些帮助。
根据乱码出现位置的不同,我把他们分为4类,然后根据具体的情况来分析解决:
1.字符串传输过程中出现乱码
这个是最底层的乱码,一般来说,使用web容器和常用的mvc框架时,其内部已经自动执行了转码的操作,所以在前后台调试的时候,突然发现某个变量在debug时变成了乱码,的确是挺讨厌的。解决的方法同样底层,我们可以强制在字符串发出和接受的两端对其进行编码/解码,比如在后台编码,前台进行解码。此时前后台传递的,就是上面提到的第三种乱码。
后台代码:
return URLEncoder.encode(optionValue.toString(), "UTF-8");
前台代码:
optionValues = decodeURIComponent(optionValues)
2.压缩文件时,内容乱码
这个是jdk里不大不小的一个bug,因为其在内部实现时默认指定了UTF-8作为唯一字符集,而且不可更改。解决这个问题有两种方法,一是修改jdk的代码,强制换掉字符集,但是这样程序就失去了移植性,所以并不推荐;二是使用第三方的压缩方法,比如这里使用的是commons-compress-1.4.1.jar里提供的方法:
代码片段:
OutputStream out = null;
BufferedOutputStream bos = null;
ZipArchiveOutputStream zaos = null;
try {
out = new FileOutputStream(new File(outputFilePath));
bos = new BufferedOutputStream(out);
zaos = new ZipArchiveOutputStream(bos);
zaos.setEncoding("UTF-8");
for (int i = 0; i < inputFilePaths.size(); i++) {
File file = new File(inputFilePaths.get(i));
zaos.putArchiveEntry(new ZipArchiveEntry(file.getName()));
IOUtils.copy(new FileInputStream(file.getAbsolutePath()), zaos);
zaos.closeArchiveEntry();
}
zaos.flush();
bos.flush();
out.flush();
} finally {
close(zaos, bos, out);
}
3.压缩文件时,文件名乱码
这个问题不大不小,解决起来倒也简单,把程序中使用的原生java.util.zip.ZipOutputStream替换成ant.jar的org.apache.tools.zip.ZipOutputStream即可,代码完全兼容,只是后者多了一个设置字符集的方法。
代码:
zipOutputStream.setEncoding("UTF-8");
4.文件传输时,文件名乱码
在实现下载操作时,后台传回的文件可能本身是好好的,但一弹出下载框就乱码了,大家可能一下子就反应过来时http的headers拼的有问题,但是这种文件名的乱码,不是简单的添上一句"charset=utf-8"就能解决的,而应该在向请求附上文件时,对文件名进行处理。
代码:
headers.setContentDispositionFormData("attachment", new String(exportFile.getName().getBytes("utf-8"), "ISO8859-1"));
PS:5.数据库乱码
问题表征为,所有的汉字变成了全角问号“?”,原因是简易客户端plsql的的字符集没有配置或者与数据源配置冲突。解决方法是配置环境变量NLS_LANG,具体到本项目组中,应该设置为SIMPLIFIED CHINESE_CHINA.ZHS16GBK。
其实这个问题在每次登陆plsql的时候都可以看到现象,就是那个登陆成功后弹出的那个对话框,仔细看就会发现软件列出了你本地和数据源的字符集不同,最极端的情况是,警告你本地没有配置从而与数据源的字符集不符,这时就一定会出现乱码了。