这段时间尝试写了一个小web项目,其中涉及到文件上传与下载,虽然网上有很多成熟的框架供使用,但为了学习我还是选择了自己编写相关的代码。当中遇到了很多问题,所以在此这分享完整的上传与下载代码供大家借鉴。
首先是上传的Servlet代码
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.util.Random; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class UpLoad extends HttpServlet { private static final long serialVersionUID = 1L; private static final Random RANDOM = new Random(); private String tempFileFolder; //临时文件存放目录 private String fileFolder; //存文件的目录 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //step 1 将上传文件流写入到临时文件 File tempFile = getTempFile(); writeToTempFile(request.getInputStream(), tempFile); //step 2从临时文件中取得上传文件流 RandomAccessFile randomFile = new RandomAccessFile(tempFile, "r"); //step 3取得文件名称 String filename = getFileName(randomFile); //step 4检查存放文件的目录在不在 checkFold(); //step 5保存文件 long fileSize = saveFile(randomFile, filename); //step 6关闭流对像,删除临时文件 randomFile.close(); tempFile.delete(); } public void init() throws ServletException { //获取项目所在目录 String contentPath = getServletContext().getRealPath("/"); this.tempFileFolder = contentPath + "files/_tmp"; this.fileFolder = contentPath+"files/_file"; } /** * 对字符串进行转码 * @param str * @return 转码后的字符串 */ private String codeString(String str) { String s = str; try { byte[] temp = s.getBytes("ISO-8859-1"); s = new String(temp, "UTF-8"); return s; } catch (UnsupportedEncodingException e) { e.printStackTrace(); return s; } } /** * 产生临时文件对象 * 会检查临时目录是否存在,如果不存在将创建目录 * @return 临时文件对象 * @throws IOException */ private File getTempFile()throws IOException{ File tempFolder = new File(this.tempFileFolder); if (!tempFolder.exists()){ tempFolder.mkdirs(); } String tempFileName = this.tempFileFolder+File.separator+Math.abs(RANDOM.nextInt()); File tempFile = new File(tempFileName); if (!tempFile.exists()){ tempFile.createNewFile(); } return tempFile; } /** * 将上传的数据流存入临时文件 * @param fileSourcel 上传流 * @param tempFile 临时文件 * @throws IOException */ private void writeToTempFile(InputStream fileSourcel,File tempFile)throws IOException{ FileOutputStream outputStream = new FileOutputStream(tempFile); byte b[] = new byte[1000]; int n ; while ((n=fileSourcel.read(b))!=-1){ outputStream.write(b,0,n); } outputStream.close(); fileSourcel.close(); } /** * 从临时文件流中提取文件名称 * @param randomFile * @return 解析的文件名称 * @throws IOException */ private String getFileName(RandomAccessFile randomFile)throws IOException{ String _line; while((_line=randomFile.readLine())!=null && !_line.contains("form-data; name="upload"")){ } String filePath = _line; String filename = filePath.replace("Content-Disposition: form-data; name="upload"; filename="", "").replace(""",""); filename=codeString(filename); randomFile.seek(0); return filename; } /** * 获取上传文件的开始位置 * 开始位置会因为from 表单的参数不同而不同 * 如果from表单只上传文件是从第四行开始 * 本例from表单还有一个title的input , 所以从第八行开始。每多一个参数就加四行。 * @param randomFile * @return 上传文件的开始位置 * @throws IOException */ private long getFileEnterPosition(RandomAccessFile randomFile)throws IOException{ long enterPosition = 0; int forth = 1; int n ; while((n=randomFile.readByte())!=-1&&(forth<=8)){ if(n==' '){ enterPosition = randomFile.getFilePointer(); forth++; } } return enterPosition; } /** * 获取上传文件的结束位置 * 结束位置会因为文件类型不同,而不同 * 压缩包是倒数第二行后 * @param randomFile * @return 文件的结束位置 * @throws IOException */ private long getFileEndPosition(RandomAccessFile randomFile)throws IOException{ randomFile.seek(randomFile.length()); long endPosition = randomFile.getFilePointer(); int j = 1; while((endPosition>=0)&&(j<=2)){ endPosition--; randomFile.seek(endPosition); if(randomFile.readByte()==' '){ j++; } } return endPosition; } /** * 检查要保存文件的文件夹是否存在 */ private void checkFold(){ File file = new File(this.fileFolder); if (!file.exists()){ file.mkdirs(); } } /** * 将临时文件解析后存放到指定的文件存放目录 * @param randomFile * @param forthEnterPosition * @param filename * @return fileSize * @throws IOException */ private long saveFile(RandomAccessFile randomFile,String filename)throws IOException{ File saveFile = new File(this.fileFolder,filename); RandomAccessFile randomAccessFile = new RandomAccessFile(saveFile,"rw"); long forthEnterPosition = getFileEnterPosition(randomFile); long endPosition = getFileEndPosition(randomFile); //从上传文件数据的开始位置到结束位置,把数据写入到要保存的文件中 randomFile.seek(forthEnterPosition); long startPoint = randomFile.getFilePointer(); while(startPoint<endPosition){ randomAccessFile.write(randomFile.readByte()); startPoint = randomFile.getFilePointer(); } long fileSize = randomAccessFile.length(); randomAccessFile.close(); return fileSize; } }
接着是下载的Servlet代码
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Download extends HttpServlet { private static final long serialVersionUID = 1L; private static final String FILEDIR="files/_file"; private String fileFolder; //存文件的目录 public Download() { super(); } public void destroy() { super.destroy(); // Put your code here } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // request.setCharacterEncoding("UTF-8"); try{ String fileName = request.getParameter("name"); OutputStream outputStream = response.getOutputStream(); //输出文件用的字节数组,每次向输出流发送600个字节 byte b[] = new byte[600]; File fileload = new File(this.fileFolder,fileName); fileName=encodeFileName(request,fileName); //客服端使用保存文件的对话框 response.setHeader("Content-disposition", "attachment;filename="+fileName); //通知客户文件的长度 long fileLength = fileload.length(); String length = String.valueOf(fileLength); response.setHeader("Content_length", length); //读取文件,并发送给客服端下载 FileInputStream inputStream = new FileInputStream(fileload); int n = 0; while((n=inputStream.read(b))!=-1){ outputStream.write(b,0,n); } }catch(FileNotFoundException fnfe){ fnfe.printStackTrace(); try{ PrintWriter out = response.getWriter(); out.println("下载的文件不存在"); out.flush(); out.close(); }catch(IOException ie){ ie.printStackTrace(); } }catch(IOException ie){ ie.printStackTrace(); try{ PrintWriter out = response.getWriter(); out.println("下载存在问题"); out.flush(); out.close(); }catch(IOException iex){ iex.printStackTrace(); } } } /** * Initialization of the servlet. <br> * * @throws ServletException if an error occurs */ public void init() throws ServletException { this.fileFolder = getServletContext().getRealPath("/")+"files/_file"; } private String encodeFileName(HttpServletRequest request,String fileName){ try{ //IE if (request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") >0){ fileName=URLEncoder.encode(fileName,"UTF-8"); }else{ fileName = new String(fileName.getBytes("UTF-8"),"ISO8859-1"); } }catch(Exception ex){ ex.printStackTrace(); } return fileName; } }