天天看點

java實作浏覽器下載下傳檔案,并解決相容各浏覽器的亂碼與字尾問題

之前用java寫了一個檔案流輸出檔案的功能,測試細節功能的時候,發現了許多問題

一、火狐浏覽器下載下傳帶中文名字的檔案會亂碼,其他浏覽器不會

1、原因:找了下資料後發現,是火狐使用了RFC 2183協定。

檔案名存在http header中的filename,Content-Disposition: attachment; filename=FILENAME,該filename參數可用于為浏覽器下載下傳資源的檔案的名稱提供建議。但是,RFC 2183中聲明檔案名隻能使用US-ASCII字元,目前大多數流行的Web浏覽器似乎允許非US-ASCII字元(由于缺乏标準)在編碼方案和檔案名的字元集規範上不同意。那麼問題是,如果檔案名“naïvefile”(沒有引号和第三個字母是U + 00EF)需要編碼到Content-Disposition頭檔案中。 

2、解決方案:是以隻需要在Content-Disposition做下處理即可:重點是filename*=utf-8'zh_cn'

byte[] source = (byte[]) result.get("exportData");
HttpServletResponse response = RequestContextHolder.getRequestAttributes().getResponse();
if (response != null) {
    response.reset();
    response.setHeader("Content-Disposition", "attachment;filename*=utf-8'zh_cn'" + URLEncoder.encode("導出檔案名.csv", "UTF-8"));
    response.setHeader("Connection", "close");
    response.setHeader("Content-Type", "application/octet-stream");
    OutputStream out = response.getOutputStream();
    out.write(source);
    out.flush();
    out.close();
}
           

二、ios系統safiri浏覽器導出任何類型檔案都變成dms字尾類型的檔案

原因:header請求中,Content-Type設定application/octet-stream,而該type類型對應Mime 類型清單剛好是dms字尾的檔案,是以safiri浏覽器就直接将該檔案生成為dms字尾的檔案了

解決方案:大部分浏覽器都可以使用通用類型application/octet-stream,但遇到特殊的如safiri,就最好是生成什麼類型的檔案,就傳對應的tpye

//這裡Content-Type傳對應的檔案類型,參考下面的MIME表
response.setHeader("Content-Type", "text/csv");
           

另附上Mime 類型清單:

擴充名 類型/子類型
application/octet-stream
323 text/h323
acx application/internet-property-stream
ai application/postscript
aif audio/x-aiff
aifc audio/x-aiff
aiff audio/x-aiff
asf video/x-ms-asf
asr video/x-ms-asf
asx video/x-ms-asf
au audio/basic
avi video/x-msvideo
axs application/olescript
bas text/plain
bcpio application/x-bcpio
bin application/octet-stream
bmp image/bmp
c text/plain
cat application/vnd.ms-pkiseccat
cdf application/x-cdf
cer application/x-x509-ca-cert
class application/octet-stream
clp application/x-msclip
cmx image/x-cmx
cod image/cis-cod
cpio application/x-cpio
crd application/x-mscardfile
crl application/pkix-crl
crt application/x-x509-ca-cert
csh application/x-csh
css text/css
dcr application/x-director
der application/x-x509-ca-cert
dir application/x-director
dll application/x-msdownload
dms application/octet-stream
doc application/msword
dot application/msword
dvi application/x-dvi
dxr application/x-director
eps application/postscript
etx text/x-setext
evy application/envoy
exe application/octet-stream
fif application/fractals
flr x-world/x-vrml
gif image/gif
gtar application/x-gtar
gz application/x-gzip
h text/plain
hdf application/x-hdf
hlp application/winhlp
hqx application/mac-binhex40
hta application/hta
htc text/x-component
htm text/html
html text/html
htt text/webviewhtml
ico image/x-icon
ief image/ief
iii application/x-iphone
ins application/x-internet-signup
isp application/x-internet-signup
jfif image/pipeg
jpe image/jpeg
jpeg image/jpeg
jpg image/jpeg
js application/x-javascript
latex application/x-latex
lha application/octet-stream
lsf video/x-la-asf
lsx video/x-la-asf
lzh application/octet-stream
m13 application/x-msmediaview
m14 application/x-msmediaview
m3u audio/x-mpegurl
man application/x-troff-man
mdb application/x-msaccess
me application/x-troff-me
mht message/rfc822
mhtml message/rfc822
mid audio/mid
mny application/x-msmoney
mov video/quicktime
movie video/x-sgi-movie
mp2 video/mpeg
mp3 audio/mpeg
mpa video/mpeg
mpe video/mpeg
mpeg video/mpeg
mpg video/mpeg
mpp application/vnd.ms-project
mpv2 video/mpeg
ms application/x-troff-ms
mvb application/x-msmediaview
nws message/rfc822
oda application/oda
p10 application/pkcs10
p12 application/x-pkcs12
p7b application/x-pkcs7-certificates
p7c application/x-pkcs7-mime
p7m application/x-pkcs7-mime
p7r application/x-pkcs7-certreqresp
p7s application/x-pkcs7-signature
pbm image/x-portable-bitmap
pdf application/pdf
pfx application/x-pkcs12
pgm image/x-portable-graymap
pko application/ynd.ms-pkipko
pma application/x-perfmon
pmc application/x-perfmon
pml application/x-perfmon
pmr application/x-perfmon
pmw application/x-perfmon
pnm image/x-portable-anymap
pot, application/vnd.ms-powerpoint
ppm image/x-portable-pixmap
pps application/vnd.ms-powerpoint
ppt application/vnd.ms-powerpoint
prf application/pics-rules
ps application/postscript
pub application/x-mspublisher
qt video/quicktime
ra audio/x-pn-realaudio
ram audio/x-pn-realaudio
ras image/x-cmu-raster
rgb image/x-rgb
rmi audio/mid
roff application/x-troff
rtf application/rtf
rtx text/richtext
scd application/x-msschedule
sct text/scriptlet
setpay application/set-payment-initiation
setreg application/set-registration-initiation
sh application/x-sh
shar application/x-shar
sit application/x-stuffit
snd audio/basic
spc application/x-pkcs7-certificates
spl application/futuresplash
src application/x-wais-source
sst application/vnd.ms-pkicertstore
stl application/vnd.ms-pkistl
stm text/html
svg image/svg+xml
sv4cpio application/x-sv4cpio
sv4crc application/x-sv4crc
swf application/x-shockwave-flash
t application/x-troff
tar application/x-tar
tcl application/x-tcl
tex application/x-tex
texi application/x-texinfo
texinfo application/x-texinfo
tgz application/x-compressed
tif image/tiff
tiff image/tiff
tr application/x-troff
trm application/x-msterminal
tsv text/tab-separated-values
txt text/plain
uls text/iuls
ustar application/x-ustar
vcf text/x-vcard
vrml x-world/x-vrml
wav audio/x-wav
wcm application/vnd.ms-works
wdb application/vnd.ms-works
wks application/vnd.ms-works
wmf application/x-msmetafile
wps application/vnd.ms-works
wri application/x-mswrite
wrl x-world/x-vrml
wrz x-world/x-vrml
xaf x-world/x-vrml
xbm image/x-xbitmap
xla application/vnd.ms-excel
xlc application/vnd.ms-excel
xlm application/vnd.ms-excel
xls application/vnd.ms-excel
xlt application/vnd.ms-excel
xlw application/vnd.ms-excel
xof x-world/x-vrml
xpm image/x-xpixmap
xwd image/x-xwindowdump
z application/x-compress
zip application/zip
csv text/csv

三、用GBK編碼還是UTF-8?

上面的問題其實還有一個原因,就是中文系統預設編碼是GBK的,是以當時生成檔案流的時候設定了GBK,但導出的時候卻用了UTF-8,是以亂碼了。必須使用統一的編碼。

ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(baos, "GBK"))
...
byte[] source = baos.toByteArray();
baos.close();
return source;

byte[] source = (byte[]) result.get("exportData");
HttpServletResponse response = DataUtils.getResponse();
if (response != null) {
    response.reset();
    //這裡設定了utf-8,不一緻
    response.setHeader("Content-Disposition", "attachment;filename*=utf-8'zh_cn'"
                        + URLEncoder.encode(result.get("subject") + ".csv", "UTF-8").replace("+", "%20"));
    response.setHeader("Connection", "close");
    response.setHeader("Content-Type", "text/csv");
    OutputStream out = response.getOutputStream();
    out.write(source);
    out.flush();
    out.close();
}
           

·1、解析:

GBK是在國家标準GB2312基礎上擴容後相容GB2312的标準(好像還不是國家标準)。GBK編碼專門用來解決中文編碼的,是雙位元組的。不論中英文都是雙位元組的。

UTF-8 編碼是用以解決國際上字元的一種多位元組編碼,它對英文使用8位(即一個位元組),中文使用24位(三個位元組)來編碼。對于英文字元較多的論壇則用UTF-8 節省空間。另外,如果是外國人通路你的GBK網頁,需要下載下傳中文語言包支援。通路UTF-8編碼的網頁則不出現這問題。可以直接通路。

GBK包含全部中文字元;UTF-8則包含全世界所有國家需要用到的字元。

經常有人問網頁編寫UTF-8和GBK哪個編碼好,根據個人需要,如果你主要做中文程式的開發,客戶也主要是中國人的話就用GBK吧,因為UTF-8編碼的中文使用了三個位元組,用GBK節省了空間。

如果做英文網站開發,還是用utf-8吧,因為utf-8中英文隻占一個位元組。GBK中英文也是兩個位元組的,并且國外客戶通路GBK要下載下傳語言包。

如果你的網站是中文的,但國外使用者也不少,最好也用UTF-8的吧。

UTF-8編碼的文字可以在各國各種支援UTF8字元集的浏覽器上顯示。

比如,如果是UTF8編碼,則在外國人的英文IE上也能顯示中文,而無需他們下載下傳IE的中文語言支援包。 是以,對于英文比較多的論壇 ,使用GBK則每個字元占用2個位元組,而使用UTF-8英文卻隻占一個位元組。

UTF8是國際編碼,它的通用性比較好,外國人也可以浏覽論壇,GBK是國家編碼,通用性比UTF8差,不過UTF8占用的資料庫比GBK大。

繼續閱讀