目录 1、把上传的文件放到WEB-INF目录下 2、文件名称(完整路径、文件名称) 3、中文乱码问题 4、上传文件同名问题(文件重命名) 5、一个目录不能存放过多的文件(存放目录打散) 6、上传的单个文件的大小限制和整个表单大小限制 7、缓存大小与临时目录 ====================================================== 1、把上传的文件放到WEB-INF目录下 如果没有把用户上传的文件存放到WEB-INF目录下,那么用户就可以通过浏览器直接访问上传的文件,这是非常危险的。 假如说用户上传了一个a.jsp文件,然后用户在通过浏览器去访问这个a.jsp文件,那么就会执行a.jsp中的内容, 如果在a.jsp中有如下语句:Runtime.getRuntime().exec("shutdown –s –t 1");,那么你就会… 通常我们会在WEB-INF目录下创建一个uploads目录来存放上传的文件,而在Servlet中找到这个目录需要 使用ServletContext的getRealPath(String)方法,例如在我的upload1项目中有如下语句: ServletContext servletContext = this.getServletContext(); String savepath = servletContext.getRealPath("/WEB-INF/uploads"); 其中savepath为:"F:\tomcat6_1\webapps\upload1\WEB-INF\uploads" 2、文件名称(完整路径、文件名称) 上传文件名称可能是完整路径: 有些浏览器获取的上传文件名称是完整路径,大部分浏览器获取的上传文件名称只是文件名称而已。 浏览器差异的问题我们还是需要处理一下的。处理这一问题也很简单,无论是否为完整路径,我们都去截取最后一个"\\"后面的内容就可以了。 String name = file1FileItem.getName(); int lastIndex = name.lastIndexOf("\\");//获取最后一个"\"的位置 if(lastIndex != -1) {//注意,如果不是完整路径,那么就不会有"\"的存在。 name = name.substring(lastIndex + 1);//获取文件名称 } response.getWriter().print(name); 3、中文乱码问题 当上传的谁的名称中包含中文时,需要设置编码,commons-fileupload组件为我们提供了两种设置编码的方式: * request.setCharacterEncoding(String):这种方式是我们最为熟悉的方式了; * fileUpload.setHeaderEncdoing(String):这种方式是commons-fileupload组件中的,优先级高与前一种。 上传文件的文件内容包含中文: 通常我们不需关心上传文件的内容,因为我们会把上传文件保存到硬盘上!也就是说,文件原来是什么样子,到服务器这边还是什么样子! 但是如果你有这样的需求,非要在控制台显示上传的文件内容,那么你可以使用fileItem.getString("utf-8")来处理编码。 文本文件内容和普通表单项内容使用FileItem类的getString("utf-8")来处理编码。 4、上传文件同名问题(文件重命名) 通常我们会把用户上传的文件保存到uploads目录下,但如果用户上传了同名文件呢?这会出现覆盖的现象。 处理这一问题的手段是使用UUID生成唯一名称,然后再使用"_"连接文件上传的原始名称。 例如,用户上传的文件是"我的一寸照片.jpg",在通过处理后,文件名称为:"891b3881395f4175b969256a3f7b6e10_我的一寸照片.jpg", 这种手段不会使文件丢失扩展名,并且因为UUID的唯一性,上传的文件同名,但在服务器端是不会出现同名问题的。 5、一个目录不能存放过多的文件(存放目录打散) 一个目录下不应该存放过多的文件,一般一个目录存放1000个文件就是上限了,如果在多,那么打开目录时就会很"卡"。 你可以尝试打印C:\WINDOWS\system32目录,你会感觉到的。也就是说,我们需要把上传的文件放到不同的目录中。 但是也不能为每个上传的文件一个目录,这种方式会导致目录过多。所以我们应该采用某种算法来"打散"!打散的方法有很多, 例如,使用日期来打散,每天生成一个目录。也可以使用文件名的首字母来生成目录,相同首字母的文件放到同一目录下。 日期打散算法:如果某一天上传的文件过多,那么也会出现一个目录文件过多的情况; 首字母打散算法:如果文件名是中文的,因为中文过多,所以会导致目录过多的现象。 我们这里使用hash算法来打散: 1.获取文件名称的hashCode:int hCode = name.hashCode(); 2.将hCode转换成16进制字符; 3.使用这个16进制的字符的前两个字符生成目录链。 int hCode = name.hashCode();//获取文件名的hashCode String dir = Integer.toHexString(hCode); //与文件保存目录连接成完整路径 savepath = savepath + "/" + dir.charAt(0) + "/" + dir.charAt(1); //因为这个路径可能不存在,所以创建成File对象,再创建目录链,确保目录在保存文件之前已经存在 new File(savepath).mkdirs(); 6、上传的单个文件的大小限制和整个表单大小限制 限制上传文件的大小很简单,ServletFileUpload类的setFileSizeMax(long)就可以了。参数就是上传文件的上限字节数, 例如servletFileUpload.setFileSizeMax(1024*10)表示上限为10KB。一旦上传的文件超出了上限, 那么就会抛出FileUploadBase.FileSizeLimitExceededException异常。我们可以在Servlet中获取这个异常, 然后向页面输出"上传的文件超出限制"。 public void doPost(HttpServletRequest request, HttpServletResponse response) throws Exception { request.setCharacterEncoding("utf-8"); DiskFileItemFactory dfif = new DiskFileItemFactory(); ServletFileUpload fileUpload = new ServletFileUpload(dfif); fileUpload.setFileSizeMax(1024 * 10); // 设置上传的单个文件的上限为10KB fileUpload.setSizeMax(1024 * 200); //设置整个请求的上限为200KB try { List<FileItem> list = fileUpload.parseRequest(request); ...... fileItem.write(file); } catch (Exception e) { // 判断抛出的异常的类型是否为FileUploadBase.FileSizeLimitExceededException // 如果是,说明上传文件时超出了限制。 if(e instanceof FileUploadBase.FileSizeLimitExceededException) { request.setAttribute("msg", "上传失败!上传的文件超出了10KB!"); request.getRequestDispatcher("/index.jsp").forward(request, response); return; } if(e instanceof FileUploadBase.SizeLimitExceededException) { request.setAttribute("msg", "上传失败!整个表单上传的文件超出了200KB!"); request.getRequestDispatcher("/index.jsp").forward(request, response); return; } throw new ServletException(e); } } 7、缓存大小与临时目录 如果上传一个蓝光电影,先把电影保存到内存中,然后再通过内存copy到服务器硬盘上,那么你的内存能吃的消么? 所以fileupload组件不可能把文件都保存在内存中,fileupload会判断文件大小是否超出10KB, 如果超出,是那么就把文件保存到硬盘上;如果没有超出,那么就保存在内存中。 10KB是fileupload默认的值,我们可以来设置它。 当文件保存到硬盘时,fileupload是把文件保存到系统临时目录,当然你也可以去设置临时目录。 public void doPost(HttpServletRequest request, HttpServletResponse response) throws Exception { DiskFileItemFactory dfif = new DiskFileItemFactory(1024*20, new File("F:\\temp")); //设置缓存大小20KB 及目录 ...... }