文件上传、下载
1 文件上传
1.1 实现文件上传条件
1)表单的提交方式必须是POST方式。(才有content-type属性)
2)有文件上传表单,表单中有<input type="file"/>的选择文件的标签
3)把表单设置为enctype="multipart/form-data",提交的数据不再是key-value对,而是字节数据
<form action="${pageContext.request.contextPath }/UploadDemo1" method="post" enctype="multipart/form-data"> 请选择文件: <input type="file" name="img"/><br/> <input type="submit" value="上传" /> </form> |
1.2 手动解析上传文件
/** * 上传文件的信息格式 * 第一行:文件的开始符 第二行:上传的文件头信息(包含文件名称) 第三行:content-type 第四行:空行 第五行:开始文件内容 文件内容结束后一行:文件的结束符(符号和文件的开始符一致) */ public class UploadDemo1 extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //得到实体内容数据 InputStream in = request.getInputStream(); //转为字符输入流 BufferedReader br = new BufferedReader(new InputStreamReader(in)); //读取文件的开始符 String startTag = br.readLine(); //读取文件名: Content-Disposition: form-data; name="img"; filename="news.txt" String line = br.readLine(); String fileName = line.substring(line.lastIndexOf("filename=\"")+10, line.lastIndexOf("\"") ); //跳过2行 br.readLine(); br.readLine(); //读取文件的实际内容 String str = null; BufferedWriter bw = new BufferedWriter(new FileWriter("E:/files/"+fileName)); while((str=br.readLine())!=null){ //读到文件结束符时退出循环 if((startTag+"--").equals(str)){ break; } //把内容写出文件中 bw.write(str); //写入换行符 bw.newLine(); bw.flush(); } //关闭 bw.close(); br.close(); } } |
2 工具实现文件上传
2.1 commons-fileupload组件
是Apache组织旗下的开源的文件上传的组件。使用非常简单易用。
导入commoms-fileuload的jar包:
commons-fileupload-1.2.2.jar 核心包
commons-io-2.1.jar 辅助包
2.2 核心的API
DiskFileItemFactory类: 用于创建上传对象,设置文件缓存区大小,设置文件缓存目录。
ServletFileUpload类: 用于在Servlet程序中实现文件上传
List<FileItem> list = parseRequest(request): 用于解析请求数据,提取和封装文件信息。
FileItem类: 封装一个文件的所有相关的信息。包含文件名称,文件大小,文件类型, 文件数据内容。
2.3文件上传的细节
(1) ServletFileUpload类:
setFileSizeMax:设置单个文件的最大容量。(超出抛异常:FileSizeLimitExceededException)
setSizeMax : 设置所有文件的最大容量。(超出抛异常:SizeLimitExceededException)
etProgressListener(new MyProgressListener());注册上传监听器
(2) FileItem类:
① file.getContentType();//得到文件类型
② file.isFormField()//判断该FileItem是否是普通文本(除file组件外的其他表单组件)
//得到普通文本控件内容 if(file.isFormField()){ String fieldName = file.getFieldName(); if("info1".equals(fieldName)){ String info1 = file.getString("utf-8"); System.out.println("描述1:"+info1); } } |
2.4 实现单文件上传
//1.创建DiskFileItemFactory类 /** * 参数一: 表示文件缓存区的大小。如果上传的文件没有超过缓存区大小,则文件不缓存;否则缓存文件,缓存到临时目录。(byte) * 参数二: 表示缓存区的临时目录。 */ DiskFileItemFactory factory = new DiskFileItemFactory(10*1024,new File("e:/temp/"));
//2.创建ServletFileUpload类 ServletFileUpload upload = new ServletFileUpload(factory); upload.setHeaderEncoding("utf-8");//通过设置文件头编码格式来解决文件名称中文乱码问题 try { //3.解析request数据(把每一个文件封装到FileItem对象中,FileItem放入List中) List<FileItem> list = upload.parseRequest(request); //取出第一个上传的文件 FileItem file = list.get(0); //得到文件名(getName()) String fileName = file.getName(); //得到文件大小 long fileSize = file.getSize(); //得到内容类型 String contentType = file.getContentType(); //得到文件数据内容 InputStream in = file.getInputStream(); /** * 4.把文件数据内容存储到服务器端的硬盘中 */ FileUtils.copyInputStreamToFile(in, new File("e:/files/"+fileName));
/** * 5.文件上传完毕,手动清理缓存文件 */ file.delete(); } catch (FileUploadException e) { e.printStackTrace(); } |
2.5 动态选择多文件上传
<html> <script type="text/javascript"> var id = 2; //添加一行 function addIten(){ var tbodyNode = document.getElementsByTagName("tbody")[0];
var trNode = document.createElement("tr"); trNode.setAttribute("id", id);
var tdNode1 = document.createElement("td"); tdNode1.innerHTML = "请选择文件:"; var tdNode2 = document.createElement("td");
var input1 = document.createElement("input"); input1.setAttribute("type", "file"); input1.setAttribute("name", "file"); var input2 = document.createElement("input"); input2.setAttribute("type", "button"); input2.setAttribute("value", "删除"); input2.setAttribute("onclick", "delItem("+id+")");
tdNode2.appendChild(input1); tdNode2.appendChild(input2); trNode.appendChild(tdNode1); trNode.appendChild(tdNode2); tbodyNode.appendChild(trNode); id++; } //删除一行(根据tr的id值删除) function delItem(id){ if(id>1){ var trNode = document.getElementById(id); var tbodyNode = document.getElementsByTagName("tbody")[0]; tbodyNode.removeChild(trNode); id--; } } //提交并且检查file属性 function checkSunbit(){ //检查file属性是否全部填上 var fileList = document.getElementsByName("file"); for(var i=0;i<fileList.length;i++){ //如果为选择file,则其value值为空 if(fileList[i].value==null || fileList[i].value==""){ alert("请选择第"+(i+1)+"个文件"); return false; } }
//提交表单 var form = document.forms['uploadForm']; form.submit(); } </script> </html> |
3文件下载
3.1 普通文件下载
使用超链接。缺点:1)暴露文件的路径 2)扩展型和安全性不好
3.2 使用servlet程序下载(推荐)
//得到需要下载的文件 //String path = this.getServletContext().getRealPath("/upload/1.png"); //File file = new File(path);
//FileInputStream in = new FileInputStream(file); //读取服务器本地的文件 InputStream in = this.getServletContext().getResourceAsStream("/upload/1.png"); /** * 处理URL编码问题 */ String fileName = file.getName(); //对文件名进行URl编码 fileName = URLEncoder.encode(fileName, "utf-8");
//判断不同浏览器 String userAgent = request.getHeader("user-agent"); String filefix = null; if(userAgent.contains("Trident")){ //IE filefix = "filename="+fileName; }else{ filefix = "filename*="+fileName; } //告诉浏览器以下载方式打开资源 response.setHeader("Content-Disposition", "attachment;"+filefix);
//把本地文件发送给浏览器 byte[] buf = new byte[1024]; int len = 0; while( (len=in.read(buf))!=-1 ){ response.getOutputStream().write(buf, 0, len); } //关闭 in.close(); |