JAVA获取sjis文件乱码_下载文件时,文件名乱码。 | 学步园

近有一个需要支持unicode的项目在上传和下载文件时遇到文件名乱码问题. 项目背景,

这个项目关键之处在于需要支持unicode以及支持Micorosoft Internet Explorer和Netscape

Navigator两种浏览器. 为了解决这个问题, 我使用以下环境进行了尝试.

J2SE : 1.5.0_04

Tomcat : 5.5.17

Microsoft Internet Explorer 6.0 with SP2

Netscape Navigator 7.1

Firefox 1.5

以及Struts 1.1 (这个基本上对此次测试不是非常重要)

上传文件

对于unicode的页面进行上传文件的时候, 我使用一个text box和一个file upload box来进行比较. 页面如下.

2147de886bfd5e7e02e20d80978d3b8a.gif

通过此页面进行文件上传后, IE, NC以及FF所传输的数据均相同. 如下

Content-Type: multipart/form-data; boundary=---------------------------282302224217945

Content-Length: 27980

-----------------------------282302224217945

Content-Disposition: form-data; name="theText"

C:/縺ゅ≠縺ゅ≠.xls

-----------------------------282302224217945

Content-Disposition: form-data; name="theFile"; filename="縺ゅ≠縺ゅ≠.xls"

Content-Type: application/vnd.ms-excel

可以看出, 对text box和file upload box中的文件名所有浏览器均采取了相同的编码. 经证实, 是上传页面的编码方式——所有浏览器均对unicode数据(utf-8)采取了本地的编码方式(这里是ms932).

在服务器端对上传的数据进行解码.

解码的方式有很多, 这里我使用最普遍以及正规的request.setCharacterEncoding的方法. 发现form表单中的text box可以被正常解码, 但是file upload box中的文件名无法

通过这种方式解码. 所以只能使用手工解码.

String fixedFileName

=

new

String(fileName.getBytes(

"

SJIS

"

),

"

UTF-8

"

);

其中SJIS是客户端系统的编码, UTF-8是客户端页面的编码.

上传文件测试中, 所有浏览器表现一致, 需要注意的是文件名和表单数据的不同处理方式.

下载文件

使用一个unicode的JSP页面, 在页面上有一个固定的超链接, 传递给服务器一个文件名. 服务器依照这个文件名把服务器端的文件传递给客户端.

下载页面

@ page language

=

"

java

"

contentType

=

"

text/html; charset=utf-8

"

%>

9b8a8a44dd1c74ae49c20a7cd451974e.png

<

meta

http-equiv

="content-type"

content

="text/html; charset=utf-8"

>

9b8a8a44dd1c74ae49c20a7cd451974e.png

<

a

href

="download.do?name=ああああ.xls"

>

ダウンロード

a

>

对于这样一个页面, 当点击超链接后, 各浏览器处理方式不同

IE会把超链接依照页面当前编码方式编码(这里是utf-8)后, 发送给服务器端

GET /nsupload/download.do?name=縺ゅ≠縺ゅ≠.xls HTTP/1.1

NC和FF会把超链接依照页面编码方式编码(这里是utf-8)后, 再通过url encoding后, 发送给服务器端

GET /nsupload/download.do?name=%E3%81%82%E3%81%82%E3%81%82%E3%81%82.xls HTTP/1.1

(经证实, E38182是「あ」的unicode代码)

在服务器收到提交的数据后, 需要对其进行解码. 需要注意的是这种方式下使用request.setCharacterEncoding无效

. 所以必须手工解码.

name

=

new

String(name.getBytes(

"

ISO-8859-1

"

),

"

UTF-8

"

);

其中ISO-8859-1是Tomcat服务器的特性, Tomcat会把所有的数据先转换为ISO-8859-1的形式. UTF-8是实际的编码方式.

在得到文件名后, 就可以正确地读取文件, 然后把文件传递给客户端了. 其中, 文件名是保存在Http报头(header)的Content-Disposition中.

response.setHeader(

"

Content-Disposition

"

,

"

inline; filename=

"

+

_filename);

//

或者

response.setHeader(

"

Content-Disposition

"

,

"

attachment; filename=

"

+

_filename);

经实验证明, 使用inline或者attachment对文件名的编码方式没有

影响.

另外一个需要设置的是Content-Type.

response.setContentType(

"

application/vnd.ms-excel

"

);

//

或者

response.setContentType(

"

application/vnd.ms-excel; charset=UTF-8

"

);

//

或者

response.setContentType(

"

application/x-download; name=

" + _filename

);

经试验证明, 使用application/*的任何形式都对文件名的编码方式没有

影响.

第二点, 经试验证明, 这里的charset设置会被三种浏览器忽略, 所以设置与否不

影响文件名的编码方式.

第三点, 经试验证明, 这里的name设置对文件名没有

任何影响.

可能还有一个属性需要注意, 就是Content-Language. 经试验证明, Content-Language有无, 或者为何值, 对文件名没有任何影响.

那么对于non-ascii的文件名如何操作才可以保证客户端可以得到正确的显示呢?

经过调查, 有三种方法(在网上搜索后认为可能这篇文章是对于这个问题探讨最深入的文章)

第一, 使用URLEncoding方法. 即对文件名进行URLEncoding.

name

=

URLEncoder.encode(name,

"

UTF-8

"

);

这种方式适用于IE, 但是不适用于NC和FF. 在这种方式下, 网络上传输的是url encoding后的ascii编码.

Content-Disposition: inline; filename=%E3%81%82%E3%81%82%E3%81%82%E3%81%82.xls

NC和FF不能对这样的文件名进行有效的解码.

619c90289a61127d6a5f8afa377e7837.gif

948c023ecbfe1eb1ffec43aeb6a1933d.gif

第二, 使用字符串字符集强行转换为本地字符集方法, 这样做的原理是JVM底层全部为unicode. 所以一旦一个字符串表示了正确的字符集而被存储后, 这个字符串会被转换为任意字符集.

原理二是, IE和FF对非url encoding的non-ascii文件名采用客户端系统本地的编码方式进行转换.

name

=

new

String(name.getBytes(

"

Shift_JIS

"

),

"

ISO-8859-1

"

);

需要注意的是, 这里的name原本是utf-8的.

在网络上传输的为

Content-Disposition: inline; filename=ああああ.xls

经过试验, IE和FF支持这种方式, NC不支持. 表现为NC无法解析文件名.

第三种, 使用Base64编码文件名. 原理是这种做法符合RFC2047

的定义.

name

=

javax.mail.internet.MimeUtility.encodeText(name,

"

UTF-8

"

,

"

B

"

);

使用到了JavaMail中的Base64编码的类MimeUtility.

在网络上传输的为经过Base64编码的ascii字符.

Content-Disposition: inline; filename==?UTF-8?B?44GC44GC44GC44GCLnhscw==?=

只有FF支持这种方式, IE表现为无法解析文件名, NC表现为忽略Base64编码.

2766d3b130c24edb192f1b1df36408e6.png

86c9e5c8468e5cc9919b536e33f0e5f7.png

上三种方法是目前来讲, 使浏览器可以正确下载non-ascii文件名的方法. 其中IE支持两种(url encoding和force

transform), FF支持两种(force transform和base64 encoding), NC一种都不支持.

关于

这次调查的结果, 对于NC多说两句, 我以为这个结果是由于NC 7.1和Tomcat 5.5不兼容造成的. Tomcat

5.5要求必须把所有报头先转变为ISO-8859-1的格式, 而NC

7.1却无法直接对ISO-8859-1进行正确的解析或者说是解析功能比较弱. 如果有时间, 我会继续验证非unicode的情况以及NC

8的情况.

---2006年9月14日21:00 补充---

在NC 8.1上进行了测试, 测试结果是NC 8.1支持方法三, 即base64 encoding.

4094241a8c9e8e6ed67019af063a21f7.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值