因為不同瀏覽器對head處理的行為不同,所以下載對話方塊中的中文檔案名稱比較麻煩.沒有統一方法,不要以為你看到的是正確的中文,換個瀏覽器
或換個版本就不一定正確了.
大多數情況下,預設轉出UTF-8的字串是可以的:
String str = "這是一個UTF-8格式編碼的中文字串.dat";
如果不是UTF-8,那麼轉換到 UTF-8的字串,大多數時候是有效.
但是同樣是UTF-8字串,IE的不同版本看到的竟然是不同效果.雖然在contentTyep中已經指明 charset=UTF-8,而且從
用戶端進看頁面編碼也是UTF-8,但不同版本的IE卻有的亂碼有的正常.
對於IE而言,全部使用url-encode,所有版本都是正確的.這是網上流行的解決方案,但是.....................
對於IE6,限制檔案名稱大約在150個字元以內,一個中文字元UTF8編碼為3個byte,再URLEncode成9個byte,所以對於IE6最多不能超過17個中文.所以這個方法不行.
使用俺8年前用的IE下載的亂碼無敵大法,當時在IE6以下的所有版本都絕不亂碼.今天測試了一下,IE7,IE8,IE9BATE也堅決不亂,又不會有17個中文字元的限制.方法:
將字串以GB18030編碼轉換為byte[],然後將每個byte置的成char進行UTF8編碼:
byte[] src = "UTF8字串".getBytes("GB18030");
byte[] buf = new byte[src.length * 3];
int pos = 0;
for(int i=0;i<src.length;i++){
char c = (char)src[i] & 0xFF;
if(c <= 0x007F && c != 0) buf[pos++] = (byte)c;
else if(c > 0x07FF){
buf[pos+2] = (byte) (0x80 | ((c >> 0 ) & 0x3F));
buf[pos+1] = (byte) (0x80 | ((c >> 6 ) & 0x3F));
buf[pos+0] = (byte) (0xE0 | ((c >> 12 ) & 0x0F));
pos += 3;
}
else{
buf[pos+1] = (byte) (0x80 | ((c >> 0) & 0x3F));
buf[pos+0] = (byte) (0xC0 | ((c >> 6 ) & 0x1F));
pos += 2;
}
}
return new String(buf,0,pos,"UTF-8");
絕對無敵....................
但是對於FF,url-encode肯定是不行了.直接輸出UTF-8,基本上測試過的版本都正確.
但是...................................
不同的容器行為又不樣.因為response.setCharacterEncoding只對實體起作用,對頭域不起作用,所以對於頭域只能手工處理.
比如tomcat,因為它預設是ISO8859_1,你通過response.setCharacterEncoding可以讓它對實體部分的處理按你指定的字元集
處理,但
response.setHeader("Content-Disposition","attachment;filename="+str);
無法控制str按指定的字元集處理,所以只能反向轉換把UTF-8轉成ISO8859_1:
str = new String(str.getBytes("UTF-8"),"ISO8859_1");
response.setHeader("Content-Disposition","attachment;filename="+str);
這樣在tomcat輸出後,大多數瀏覽器接收到的 byte[]是UTF-8格式的,能正確處理(IE還是存在版本問題),但這種方案又和容器偶合了.
如果FF不和容器偶合的話,可以進行base64編碼,就象IE進行urlencode編碼一樣.
我KAO,這不是折騰人嗎?
那麼要盡量做到通用,先要判斷瀏覽器:
String agent = request.getHeader("User-Agent");
if(agent == null) xxxx;
agent = agent.toUpperCase();
if(agent.indexOf("MSIE") != -1) str = URLEncoder.encode(str);
else if(agent.indexOf("FIREFOX") != -1) str = Base64Encoder.encode(str);
else{
............................
}
餘下的瀏覽器怎麼辦呢?經過測試Opera/Chrome都只能解釋UTF-8的中文名.所以
else{
............................
}將這樣:
else if(serverTyep.equals("tomcat")){
str = new String(str.getBytes("UTF-8"),"ISO8859_1");
}
else{
//其它容器是否要轉碼看它預設用什麼字元集處理.比如resin就不用任何編碼,只要是UTF-8格式的就正確
}
對於服務端的不相容,其它平台不一定有這個問題.但是對於用戶端的不相容,任何平台都會有這個問題.要針對不同瀏覽器做不同的處理.