晚上跟zh等同志一起看了下文件下载的中文问题,问题解决,并且收获不小:
1、java的char类型是16bit,而不是c/c++中的8bit,所以char和byte之间的转换会造成严重的精度损失。而Java的char是Unicode的。
2、java中String是基于char[]的,也就是说这个String天生就可以表示Unicode。所以如果从byte[]创建一个String就会涉及到一个严重的策略问题,是一个byte转一个String字还是两个byte转一个String字。
3、所以我们常用的java转码中的语句somestr = new String(somestr.getBytes(),"ISO-8859-1")与somestr = new String(somestr.getBytes(),"GB2312")之间是有很大区别的,它们关系到从一个byte变两个byte或反过来。
4、所以,对于单精度的"ISO-8859-1"与双精度的GB2312、GBK、utf-8处理的时候一定要分清,而且它也可以解决很多的问题。而如果你好好了解GB2312与GBK的效果其实很类似,他们只有部分的编码覆盖度上的区别,大部分字符是通用的,可是"ISO-8859-1"却与他们完全不同。
5、还有一个有意思的地方:java.io.Writer与java.io.InputStream下面的东西有个明显的区别,前者接受char[],而后者接受byte[]。其实理解一下,他们之间的转换其实正好需要String的单字节编码与双字节编码的区别,我们可以用它们完成有意思的转换。在它们的沟通过程中我们如果使用buffer,则需要String作为中间者进行转换,算个小trick吧。
6、从这里,我们引出今天解决的中文文件下载的问题中的有意思的地方:
<%@ page language="java" import="java.io.PrintWriter"
%><%
String filename = (String)request.getAttribute("downloadFileName");
String filepath = (String)request.getAttribute("downloadFileUrl");
filename = new String(filename.getBytes(),"ISO-8859-1");
if(filename != null && filepath != null) {
response.setContentType("APPLICATION/OCTET-STREAM");
response.setHeader("Content-Disposition",
"attachment; filename=\"" + filename + "\"");
java.io.FileInputStream fileInputStream =
new java.io.FileInputStream(filepath);
java.io.File file = new java.io.File(filepath);
response.setContentLength((new Long(file.length()).intValue()));
PrintWriter pw = response.getWriter();
byte[] charArray = new byte[4096];
int len;
while ((len=fileInputStream.read(charArray)) != -1) {
String s = new String(charArray,"ISO-8859-1");
pw.write(s);
}
pw.flush();
pw.close();
fileInputStream.close();
}
%>