文件上传

在这里插入图片描述
简介

文件上传和下载是java web中常见的操作,文件上传主要是将文件通过IO流传放到服务器的某一个特定的文件夹下,而文件下载则是与文件上传相反,将文件从服务器的特定的文件夹下的文件通过IO流下载到本地。

对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件。这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,struts上传的功能就是基于这个实现的。common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。

文件上传

磁盘文件项工厂disk file item factory

1、文件上传页面和消息提示页面
核心API介绍
1.DiskFileItemFactory
作用:可以设置缓存大小以及临时文件保存位置.
默认缓存大小是 10240(10k).
临时文件默认存储在系统的临时文件目录下.(可以在环境变量中查看)

		1.new DiskFileItemFactory();
			缓存大小与临时文件存储位置使用默认的.
			
		2.DiskFileItemFactory(int sizeThreshold, File repository) 
			sizeThreshold :缓存大小
			repository:临时文件存储位置
			
		注意,对于无参数构造,也可以设置缓存大小以及临时文件存储位置.	
		 setSizeThreshold(int sizeThreshold)
		 setRepository(File repository)
		
	2.ServletFileUpload
		1.ServletFileUpload upload=new ServletFileUpload(factory);
		 创建一个上传工具,指定使用缓存区与临时文件存储位置.
		
		2.List<FileItem> items=upload.parseRequest(request);
			它是用于解析request对象,得到所有上传项.每一个FileItem就相当于一个上传项.
			
		3.boolean flag=upload.isMultipartContent(request);
			用于判断是否是上传.
			可以简单理解,就是判断encType="multipart/form-data";
			
		4.设置上传文件大小
			void setFileSizeMax(long fileSizeMax) 设置单个文件上传大小 
			void  setSizeMax(long sizeMax) 设置总文件上传大小 
		5.解决上传文件中文名称乱码
			setHeaderEncoding("utf-8");
			注意:如果使用reqeust.setCharacterEncoding("utf-8")也可以,但不建议使用。

ServletFileUpload的讲解.

    1.ServletFileUpload upload=new ServletFileUpload(factory);

            创建一个上传工具,指定使用缓存区与临时文件存储位置.

    2.List<FileItem> items=upload.parseRequest(request);

            它是用于解析request对象,得到所有上传项.每一个FileItem就相当于一个上传项.

    3.boolean flag=upload.isMultipartContent(request);

            用于判断是否是上传.

            可以简单理解,就是判断encType="multipart/form-data";

    4.设置上传文件大小.

            void setFileSizeMax(long fileSizeMax) 设置单个文件上传大小 .

            void  setSizeMax(long sizeMax) 设置总文件上传大小 .

    5.解决上传文件中文名称乱码.

            setHeaderEncoding("utf-8");

            注意:如果使用reqeust.setCharacterEncoding("utf-8")也可以,但不建议使用。

FileItem类:

    1.isFormField    

                用于判断是否是上传组件.

                如果是<input type="file">返回的就是false,否则返回true.

    2.getFieldName();

                返回值String,得到组件名称  <input name="">

    3.getName();

                返回值是String,得到的是上传文件的名称.

                注意:浏览器不同,它们得到的效果不一样。

                            1.包含全路径名称  例如: C:\Users\Administrator\Desktop\a.txt

                            2.只包含上传文件名称 例如:a.txt

    4.getString();

                这个方法可以获取非上传组件的内容,相当于  getParameter方法作用。

                问题:如果信息是中文,会出现乱码,解决方案  getString("utf-8");

                如果是上传组件,上传的文件是文本文件,可以获取到文件文件的内容。

                但是如果不是文件文件,例如:是一张图片,这样获取合适吗?

    5.获取上传文件的内容,保存到服务器端.

                item.getInputStream();它是用于读取上传文件内容的输入流.

                使用文件复制操作就可以完成文件上传。

     6.删除临时文件

                item.delete();

    总结:关于文件上传时的乱码问题:

    1.上传文件名称乱码

            ServletFileUpload.setHeaderEncoding("utf-8");

    2.非上传组件内容乱码

            FileItem.getString("utf-8");

    3.思考:上传文件信息是否会乱码,需要解决吗?

            不需要解决,因为我们在上传时,使用的字节流来进行复制。

问题

文件上传兼容浏览器问题

int idx=filename.lastIndexOf("\\");
if(inx!=-1){
//老版本浏览器
filename=filename.substring(idx+1);
}

UUID避免重复文件名

同一目录下文件过多

目录分离算法来进行文件分类:
唯一文件名取得hashcode&0xf来作为一级目录
右移4位&0xf作为二级目录,以此类推

upload.jsp页面的代码如下:

<%@ page language="java" pageEncoding="UTF-8"%>
 
<!DOCTYPE HTML>
 
<html>
 
  <head>
 
    <title>文件上传</title>
 
   </head>
 
 
 
   <body>
 
     <form action="${pageContext.request.contextPath}/servlet/uploadHandleServlet2" enctype="multipart/form-data" method="post"         上传用户:<input type="text"name="username"><br/>
 
         上传文件1<input type="file" name="file1"><br/>
 
         上传文件2<input type="file" name="file2"><br/>
 
         <input type="submit" value="提交">
 
     </form>
 
   </body>
 
</html>

在文件上传的页面要用enctype=“multipart/form-data” method="post"来表示进行文件上传。

2、处理文件上传的Servlet

public class UploadHandleServlet extends HttpServlet{
 
 
 
    @Override
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
        //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
 
        String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
 
        File file = new File(savePath);
 
        if(!file.exists()&&!file.isDirectory()){
 
            System.out.println("目录或文件不存在!");
 
            file.mkdir();
 
        }
 
        //消息提示
 
        String message = "";
 
        try {
 
            //使用Apache文件上传组件处理文件上传步骤:
 
            //1、创建一个DiskFileItemFactory工厂
 
            DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
 
            //2、创建一个文件上传解析器
 
            ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
 
            //解决上传文件名的中文乱码
 
            fileUpload.setHeaderEncoding("UTF-8");
 
            //3、判断提交上来的数据是否是上传表单的数据
 
            if(!fileUpload.isMultipartContent(request)){
 
                //按照传统方式获取数据
 
                return;
 
            }
 
            //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
 
            List<FileItem> list = fileUpload.parseRequest(request);
 
            for (FileItem item : list) {
 
                //如果fileitem中封装的是普通输入项的数据
 
                if(item.isFormField()){
 
                    String name = item.getFieldName();
 
                    //解决普通输入项的数据的中文乱码问题
 
                    String value = item.getString("UTF-8");
 
                    String value1 = new String(name.getBytes("iso8859-1"),"UTF-8");
 
                    System.out.println(name+"  "+value);
 
                    System.out.println(name+"  "+value1);
 
                }else{
 
                    //如果fileitem中封装的是上传文件,得到上传的文件名称,
 
                    String fileName = item.getName();
 
                    System.out.println(fileName);
 
                    if(fileName==null||fileName.trim().equals("")){
 
                        continue;
 
                    }
 
                    //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如:  c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
 
                    //处理获取到的上传文件的文件名的路径部分,只保留文件名部分
 
                    fileName = fileName.substring(fileName.lastIndexOf(File.separator)+1);
 
                    //获取item中的上传文件的输入流
 
                    InputStream is = item.getInputStream();
 
                    //创建一个文件输出流
 
                    FileOutputStream fos = new FileOutputStream(savePath+File.separator+fileName);
 
                    //创建一个缓冲区
 
                    byte buffer[] = new byte[1024];
 
                    //判断输入流中的数据是否已经读完的标识
 
                    int length = 0;
 
                    //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
 
                    while((length = is.read(buffer))>0){
 
                        //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
 
                        fos.write(buffer, 0, length);
 
                    }
 
                    //关闭输入流
 
                    is.close();
 
                    //关闭输出流
 
                    fos.close();
 
                    //删除处理文件上传时生成的临时文件
 
                    item.delete();
 
                    message = "文件上传成功";
 
                }
 
            }
 
        } catch (FileUploadException e) {
 
            // TODO Auto-generated catch block
 
            e.printStackTrace();
 
            message = "文件上传失败";
 
        }
 
        request.setAttribute("message",message);
 
        request.getRequestDispatcher("/message.jsp").forward(request, response);
 
    }
 
 
 
    @Override
 
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
        doGet(request, response);
 
    }
}
 

3、文件上传的细节

上述的代码虽然可以成功将文件上传到服务器上面的指定目录当中,但是文件上传功能有许多需要注意的小细节问题,以下列出的几点需要特别注意的:

(1)、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。

(2)、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。

(3)、为防止一个目录下面出现太多文件,要使用hash算法打散存储。

(4)、要限制上传文件的最大值。

(5)、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。

4、改进后的servlet

public class UploadHandleServlet1 extends HttpServlet{
 
 
 
    @Override
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
        //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
 
        String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
 
        //上传时生成的临时文件保存目录
 
        String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
 
        File file = new File(tempPath);
 
        if(!file.exists()&&!file.isDirectory()){
 
            System.out.println("目录或文件不存在!");
 
            file.mkdir();
 
        }
 
        //消息提示
 
        String message = "";
 
        try {
 
            //使用Apache文件上传组件处理文件上传步骤:
 
            //1、创建一个DiskFileItemFactory工厂
 
            DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
 
            //设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。
 
            diskFileItemFactory.setSizeThreshold(1024*100);
 
            //设置上传时生成的临时文件的保存目录
 
            diskFileItemFactory.setRepository(file);
 
            //2、创建一个文件上传解析器
 
            ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
 
            //解决上传文件名的中文乱码
 
            fileUpload.setHeaderEncoding("UTF-8");
 
            //监听文件上传进度
 
            fileUpload.setProgressListener(new ProgressListener(){
 
                public void update(long pBytesRead, long pContentLength, int arg2) {
 
                    System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);
 
                }
 
            });
 
            //3、判断提交上来的数据是否是上传表单的数据
 
            if(!fileUpload.isMultipartContent(request)){
 
                //按照传统方式获取数据
 
                return;
 
            }
 
            //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
 
            fileUpload.setFileSizeMax(1024*1024);
 
            //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
 
            fileUpload.setSizeMax(1024*1024*10);
 
            //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
 
            List<FileItem> list = fileUpload.parseRequest(request);
 
            for (FileItem item : list) {
 
                //如果fileitem中封装的是普通输入项的数据
 
                if(item.isFormField()){
 
                    String name = item.getFieldName();
 
                    //解决普通输入项的数据的中文乱码问题
 
                    String value = item.getString("UTF-8");
 
                    String value1 = new String(name.getBytes("iso8859-1"),"UTF-8");
 
                    System.out.println(name+"  "+value);
 
                    System.out.println(name+"  "+value1);
 
                }else{
 
                    //如果fileitem中封装的是上传文件,得到上传的文件名称,
 
                    String fileName = item.getName();
 
                    System.out.println(fileName);
 
                    if(fileName==null||fileName.trim().equals("")){
 
                        continue;
 
                    }
 
                    //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如:  c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
 
                    //处理获取到的上传文件的文件名的路径部分,只保留文件名部分
 
                    fileName = fileName.substring(fileName.lastIndexOf(File.separator)+1);
 
                    //得到上传文件的扩展名
 
                    String fileExtName = fileName.substring(fileName.lastIndexOf(".")+1);
 
                    if("zip".equals(fileExtName)||"rar".equals(fileExtName)||"tar".equals(fileExtName)||"jar".equals(fileExtName)){
 
                        request.setAttribute("message", "上传文件的类型不符合!!!");
 
                        request.getRequestDispatcher("/message.jsp").forward(request, response);
 
                        return;
 
                    }
 
                    //如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法
 
                    System.out.println("上传文件的扩展名为:"+fileExtName);
 
                    //获取item中的上传文件的输入流
 
                    InputStream is = item.getInputStream();
 
                    //得到文件保存的名称
 
                    fileName = mkFileName(fileName);
 
                    //得到文件保存的路径
 
                    String savePathStr = mkFilePath(savePath, fileName);
 
                    System.out.println("保存路径为:"+savePathStr);
 
                    //创建一个文件输出流
 
                    FileOutputStream fos = new FileOutputStream(savePathStr+File.separator+fileName);
 
                    //创建一个缓冲区
 
                    byte buffer[] = new byte[1024];
 
                    //判断输入流中的数据是否已经读完的标识
 
                    int length = 0;
 
                    //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
 
                    while((length = is.read(buffer))>0){
 
                        //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
 
                        fos.write(buffer, 0, length);
 
                    }
 
                    //关闭输入流
 
                    is.close();
 
                    //关闭输出流
 
                    fos.close();
 
                    //删除处理文件上传时生成的临时文件
 
                    item.delete();
 
                    message = "文件上传成功";
 
                }
 
            }
 
        } catch (FileUploadBase.FileSizeLimitExceededException e) {
 
            e.printStackTrace();
 
            request.setAttribute("message", "单个文件超出最大值!!!");
 
            request.getRequestDispatcher("/message.jsp").forward(request, response);
 
            return;
 
        }catch (FileUploadBase.SizeLimitExceededException e) {
 
            e.printStackTrace();
 
            request.setAttribute("message", "上传文件的总的大小超出限制的最大值!!!");
 
            request.getRequestDispatcher("/message.jsp").forward(request, response);
 
            return;
 
        }catch (FileUploadException e) {
 
            // TODO Auto-generated catch block
 
            e.printStackTrace();
 
            message = "文件上传失败";
 
        }
 
        request.setAttribute("message",message);
 
        request.getRequestDispatcher("/message.jsp").forward(request, response);
 
    }
 
 
 
    @Override
 
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
        doGet(request, response);
 
    }
 
    //生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称
 
    public String mkFileName(String fileName){
 
        return UUID.randomUUID().toString()+"_"+fileName;
 
    }
 
    public String mkFilePath(String savePath,String fileName){
 
        //得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址
 
        int hashcode = fileName.hashCode();
 
        int dir1 = hashcode&0xf;
 
        int dir2 = (hashcode&0xf0)>>4;
 
        //构造新的保存目录
 
        String dir = savePath + "\\" + dir1 + "\\" + dir2;
 
        //File既可以代表文件也可以代表目录
 
        File file = new File(dir);
 
        if(!file.exists()){
 
            file.mkdirs();
 
        }
        return dir;
    }
}
 

5、如果在文件上传中IO流成为了系统的性能瓶颈,可以考虑使用NIO来提高性能。改进servlet代码如下:

public class UploadHandleServlet2 extends HttpServlet{
 
 
 
    @Override
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
        //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
 
        String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
 
        //上传时生成的临时文件保存目录
 
        String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
 
        File file = new File(tempPath);
 
        if(!file.exists()&&!file.isDirectory()){
 
            System.out.println("目录或文件不存在!");
 
            file.mkdir();
 
        }
 
        //消息提示
 
        String message = "";
 
        try {
 
            //使用Apache文件上传组件处理文件上传步骤:
 
            //1、创建一个DiskFileItemFactory工厂
 
            DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
 
            //设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。
 
            diskFileItemFactory.setSizeThreshold(1024*100);
 
            //设置上传时生成的临时文件的保存目录
 
            diskFileItemFactory.setRepository(file);
 
            //2、创建一个文件上传解析器
 
            ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
 
            //解决上传文件名的中文乱码
 
            fileUpload.setHeaderEncoding("UTF-8");
 
            //监听文件上传进度
 
            fileUpload.setProgressListener(new ProgressListener(){
 
                public void update(long pBytesRead, long pContentLength, int arg2) {
 
                    System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);
 
                }
 
            });
 
            //3、判断提交上来的数据是否是上传表单的数据
 
            if(!fileUpload.isMultipartContent(request)){
 
                //按照传统方式获取数据
 
                return;
 
            }
 
            //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
 
            fileUpload.setFileSizeMax(1024*1024);
 
            //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
 
            fileUpload.setSizeMax(1024*1024*10);
 
            //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
 
            List<FileItem> list = fileUpload.parseRequest(request);
 
            for (FileItem item : list) {
 
                //如果fileitem中封装的是普通输入项的数据
 
                if(item.isFormField()){
 
                    String name = item.getFieldName();
 
                    //解决普通输入项的数据的中文乱码问题
 
                    String value = item.getString("UTF-8");
 
                    String value1 = new String(name.getBytes("iso8859-1"),"UTF-8");
 
                    System.out.println(name+"  "+value);
 
                    System.out.println(name+"  "+value1);
 
                }else{
 
                    //如果fileitem中封装的是上传文件,得到上传的文件名称,
 
                    String fileName = item.getName();
 
                    System.out.println(fileName);
 
                    if(fileName==null||fileName.trim().equals("")){
 
                        continue;
 
                    }
 
                    //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如:  c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
 
                    //处理获取到的上传文件的文件名的路径部分,只保留文件名部分
 
                    fileName = fileName.substring(fileName.lastIndexOf(File.separator)+1);
 
                    //得到上传文件的扩展名
 
                    String fileExtName = fileName.substring(fileName.lastIndexOf(".")+1);
 
                    if("zip".equals(fileExtName)||"rar".equals(fileExtName)||"tar".equals(fileExtName)||"jar".equals(fileExtName)){
 
                        request.setAttribute("message", "上传文件的类型不符合!!!");
 
                        request.getRequestDispatcher("/message.jsp").forward(request, response);
 
                        return;
 
                    }
 
                    //如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法
 
                    System.out.println("上传文件的扩展名为:"+fileExtName);
 
                    //获取item中的上传文件的输入流
 
                    InputStream fis = item.getInputStream();
 
                    //得到文件保存的名称
 
                    fileName = mkFileName(fileName);
 
                    //得到文件保存的路径
 
                    String savePathStr = mkFilePath(savePath, fileName);
 
                    System.out.println("保存路径为:"+savePathStr);
 
                    //创建一个文件输出流
 
                    FileOutputStream fos = new FileOutputStream(savePathStr+File.separator+fileName);
 
                    //获取读通道
 
                    FileChannel readChannel = ((FileInputStream)fis).getChannel();
 
                    //获取读通道
 
                    FileChannel writeChannel = fos.getChannel();
 
                    //创建一个缓冲区
 
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
 
                    //判断输入流中的数据是否已经读完的标识
 
                    int length = 0;
 
                    //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
 
                    while(true){
 
                        buffer.clear();
 
                        int len = readChannel.read(buffer);//读入数据
 
                        if(len < 0){
 
                            break;//读取完毕
 
                        }
 
                        buffer.flip();
 
                        writeChannel.write(buffer);//写入数据
 
                    }
 
                    //关闭输入流
 
                    fis.close();
 
                    //关闭输出流
 
                    fos.close();
 
                    //删除处理文件上传时生成的临时文件
 
                    item.delete();
 
                    message = "文件上传成功";
 
                }
 
            }
 
        } catch (FileUploadBase.FileSizeLimitExceededException e) {
 
            e.printStackTrace();
 
            request.setAttribute("message", "单个文件超出最大值!!!");
 
            request.getRequestDispatcher("/message.jsp").forward(request, response);
 
            return;
 
        }catch (FileUploadBase.SizeLimitExceededException e) {
 
            e.printStackTrace();
 
            request.setAttribute("message", "上传文件的总的大小超出限制的最大值!!!");
 
            request.getRequestDispatcher("/message.jsp").forward(request, response);
 
            return;
 
        }catch (FileUploadException e) {
 
            // TODO Auto-generated catch block
 
            e.printStackTrace();
 
            message = "文件上传失败";
 
        }
 
        request.setAttribute("message",message);
 
        request.getRequestDispatcher("/message.jsp").forward(request, response);
 
    }
 
 
 
    @Override
 
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
        doGet(request, response);
 
    }
 
    //生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称
 
    public String mkFileName(String fileName){
 
        return UUID.randomUUID().toString()+"_"+fileName;
 
    }
 
    public String mkFilePath(String savePath,String fileName){
 
        //得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址
 
        int hashcode = fileName.hashCode();
 
        int dir1 = hashcode&0xf;
 
        int dir2 = (hashcode&0xf0)>>4;
 
        //构造新的保存目录
 
        String dir = savePath + "\\" + dir1 + "\\" + dir2;
 
        //File既可以代表文件也可以代表目录
 
        File file = new File(dir);
 
        if(!file.exists()){
 
            file.mkdirs();
 
        }
 
        return dir;
 
    }
 
}
 

文件下载

超链接的方式

在这里插入图片描述

<td align="center"">
<a href="<c:url value="/bbsfile?filename=20150417.XLS&saveasfilename=template.xls"/>">下载导入模板</a>
</td> 

浏览器支持可以打开,浏览器不支持就会提示下载

1、文件下载就是向客户端响应字节数据!

以前我们响应的都是html的字符数据,直接展示在浏览器上,现在要作为一个文件下载下来,而不是直接展示在浏览器上,

把一个文件变成字节数组,使用response.getOutputStream()来响应给浏览器!!!

2、下载的要求:两个头一个流!

Content-Type:你传递给客户端的文件是什么MIME类型,例如:image/pjpeg

    * 通过文件名称调用ServletContext的getMimeType()方法,得到MIME类型!

Content-Disposition:它的默认值为inline,表示在浏览器窗口中打开!attachment;filename=xxx

    * 在filename=后面跟随的是显示在下载框中的文件名称!

流:要下载的文件数据!

    * 自己new一个输入流即可!

3、编写文件下载代码

   描述:被下载的资源必须放到 WEB-INF 安全目录下(只要用户不能通过浏览器直接访问就OK),然后通过Servlet完成下载。在jsp页面中给出超链接,链接到DownloadServlet,并提供要下载的文件名称。然后DownloadServlet获取文件的真实路径,然后把文件写入到response.getOutputStream()流中。
download.jsp

  <body>

    This is my JSP page. <br>

    <a href="<c:url value='/DownloadServlet?filename=a.avi'/>">a.avi</a><br/>

    <a href="<c:url value='/DownloadServlet?filename=a.jpg'/>">a.jpg</a><br/>

    <a href="<c:url value='/DownloadServlet?filename=a.txt'/>">a.txt</a><br/>

  </body>

DownloadServlet.java (使用了commons-io-1.4.jar工具包)

   @Override

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        request.setCharacterEncoding("utf-8");

        response.setContentType("text/html;charset=utf-8");

        /*

         * 两个头一个流

         * 1. Content-Type

         * 2. Content-Disposition

         * 3. 流:下载文件的数据

         */

        //得到前台传过来的文件名

        String filename = request.getParameter("filename");

        //该文件的在服务器的路径

        String filepath = this.getServletContext().getRealPath("/WEB-INF/uploads/" + filename);

        File file = new File(filepath);

        if(!file.exists()) {

            response.getWriter().print("您要下载的文件不存在!");

            return;

        }else{
            //设置2个响应头
            //通过文件名称获取MIME类型(根据文件名的后缀)
            response.setHeader("Content-Type", this.getServletContext().getMimeType(filename));
           //该头信息,可以使下载框显示下载的文件名

            response.setHeader("Content-Disposition", "attachment;filename=" + filenameEncoding("流光%飞舞.mp3", request));


            // 1个流

            FileInputStream input = new FileInputStream(file);

            ServletOutputStream output = response.getOutputStream();// 获取绑定了响应端的流

            IOUtils.copy(input, output);//把输入流中的数据写入到输出流中。

            input.close();

        }
    }
 // 解决不同浏览器中文乱码问题,用来对下载的文件名称进行编码的!

    public static String filenameEncoding(String filename, HttpServletRequest request) throws IOException {

        String agent = request.getHeader("User-Agent"); //获取浏览器

        if (agent.contains("Firefox")) { //火狐用的是BASE64Encoder 来编码和解码

            filename = "=?utf-8?B?" + new BASE64Encoder().encode(filename.getBytes("utf-8")) + "?=";

        } else { //其他浏览器用的都是URLEncoder 来编码和解码

            filename = URLEncoder.encode(filename, "utf-8");

        }

        return filename;

    }

4、下载的细节

 4.1设置响应头的目的:

       Content-Type  文件的MIME类型

       Content-Disposition  响应头属性有两种类型:inline 和 attachment.

             inline :将文件内容直接显示在页面 (默认)。

             attachment:弹出对话框让用户下载文件。添加content-disposition头,指定了在下载框中显示的文件名称。

                   如:response.setHeader("Content-Disposition", "attachment;filename=白冰.jpg" );

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值