最近用到SmartUpload 来上传文件。SmartUpload对文件的上传和下载虽然很方便,但其对中文支持不足。所以经常会出现乱码的问题,瞬间崩溃的感觉。
本人现在用 SmartUpload 的上传部分,姑且只解决上传出现的乱码问题,下载部分可自行研究。
大家都知道,Java读取文件的方式总体可以分为两类:按字节读取和按字符读取。其实字符流可以看做是一种包装流,它的底层还是采用字节流来读取字节。那么Java按字节读取文件主要用InputStream.read() 方法来读取。这个方法并不能设置读取的编码方式,因为从输入流里读取的字节编码取决于被读取的文件自身的编码。
既然读文件要使用和文件编码一致的编码,那Eclipse是怎么读取Java文件的呢?
经过baidu后发现:
① javac在控制台编译java类文件时默认采用了操作系统默认的GBK编码解码文件,当然使用javac的encoding参数来制定我们的解码编码,如下::javac -encoding UTF-8 Demo.java
② Eclipse中编译java文件时,Eclipse会自动识别了我们java源文件的文件编码,然后采取了正确的encoding参数来编译我们的java源文件。
言归正传,SmartUpload 在什么情况下会出现乱码,为什么会出现乱码。以下分几种情况细说:
为解决 SmartUpload的各种乱码,我利用反编译工具查看 SmartUpload.jar 包里的二进制文件,以方便修改SmartUpload 的源代码。假设我的项目,jsp.....都是UTF-8的编码方式。
1. 当使用 SmartUpload 上传文件时且文件名含有中文时会出现乱码,但是这并不影响我们上传文件,因为我们上传到服务器之后的文件名一般都是我们自己取的,和客户端的文件名没有半毛钱关系,所以这个乱码问题我也是到最后才发现,当我们在 SmartUpload 类的getDataHeader() 方法中将返回结果打印出来,上传”专卖店.png”的图片时,会输出“Content-Disposition: form-data;name="image"; filename="涓撳崠搴?png"”, 可以看出文件文发生了乱码。发生乱码的原因是 jsp文件采用的是 UTF-8的编码方式,为SmartUpload 的 m_response 的CharacterEncoding为ISO-8859-1。当我们在生成返回值字符串是为其指定编码方式为 UTF-8 时就不会出现乱码,即str = new String(this.m_binArray, i, j - i + 1,"UTF-8")。这时打印的是:“Content-Disposition: form-data; name="image";filename="专卖店.png"”。
2. 当使用 SmartUpload上传文件时,在form 表单里有一个text 的input时,text的值含有中文字符,在后台利用smartUpload.getRequest().getParameter("name")时也会出现乱码。这个问题比上个问题更纠结,因为查看源码之后发现jsp和SmartUpload 的Request的CharacterEncoding编码方式都是UTF-8,这样就无从下手了。当然也想过其他办法,最容易相到的就是处理乱码字符串,使其变得不是乱码,所以本人写了一个静态方法(StringUtils. toUTF8ByGBK)将乱码的字符串转换成UTF-8编码的字符串,发现暂时能解决问题。后来才发现没有问题只是巧合。例如:
<span style="white-space:pre"> </span>String test = "oppo专卖";
System.out.println(test);
System.out.println(test.length());
Strings = new String(test.getBytes(), "GBK");
Stringstr = toUTF8ByGBK(s);
System.out.println(str);
System.out.println(str.length());
结果:
oppo专卖
6
oppo专卖
6
--------------------------------------------------
But
<span style="white-space:pre"> </span>String test = "oppo专卖店";
<span style="white-space:pre"> </span>System.out.println(test);
<span style="white-space:pre"> </span>System.out.println(test.length());
<span style="white-space:pre"> </span>Strings = new String(test.getBytes(), "GBK");
<span style="white-space:pre"> </span>Stringstr = toUTF8ByGBK(s);
<span style="white-space:pre"> </span>System.out.println(str);
<span style="white-space:pre"> </span>System.out.println(str.length());
结果:
oppo专卖店
7
oppo专卖�?
8
第二种情况连个编码不一样的字符串的长度都不一样,查资料发现是因为:GBK编码是一个中文2个字节,而UTF-8编码是一个中文3个字节。这个问题在刚开始的时候也说过。
这个简单粗暴的方法还是不能解决问题,那么就要另辟蹊径了。最容易想到的就是放弃SmartUpload,改用commons-fileupload 。本人用过一次commons-fileupload 。后台处理相当麻烦,代码一大推。虽然可以解决这个乱码问题,但是秉着少写代码的原则(在后期会多次需要上传文件),所以继续修改SmartUpload 的源代码。经过多次debug 后知道问题出现在SmartUpload 的load() 里。在 load()方法中当表单遍历到不是文件的时候会 执行this.m_formRequest.putParameter(str2,(String)localObject)。这行代码就是把表单里面text 的参数通过键值对的方式放到SmartUpload的Request的Hashtable里面。在这里就出现了乱码。追究上面代码,即localObject 是怎么来的,localObject = new String(this.m_binArray, this.m_startData, this.m_endData- this.m_startData + 1);纠结到这里大家应该知道问题出现在哪了。 在new localObject的时候采用的默认编码方式和我们jsp 或Servlet的编码方式不一样,这里只需要改某一个使其一样就OK了。
3. 当使用 SmartUpload下载文件时,当文件名含有中文时也会出现乱码。同样修改源代码可以很方便的解决问题。