11
Jan
计算机与 InternetJan 11th, 2006tin
晚上跟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();}%>