JavaEE_文件上传、文件下载

一、 文件上传

1、本质就是I/O读写

  • 客户端(浏览器)发送文件,发送的是http协议。文件的内容写出去,客户端本地使用输入流,然后将内容用网络输出流输出。
  • 服务器(web容器)接收文件,用网络输入流把文件的内容读过来,然后服务器本地输出流读取。

2、可以使用别人写好的包进行文件上传,常用的是Apache组织提供的一个包。
commons-fileupload.jar commons-io.jar去官方网站下载:www.apache.org,下拉至最下面,点击commons,选择下载fileupload,io

3、上传的步骤:
浏览器端:

1)写一个jsp/html做展示(选择某一个文件)
2)必须通过表单提交
3)必须使用post方式
规定:ServletFileUpload类中一个属性 post
字节数:get没有限制,肯定通过URL拼串儿
每一个不同浏览器对于URL处理长度有所不同
IE 2048+35 IE 4076
Google 8182 FireFox 65535
Safari 80000 Opera 190000
post没有限制,需要web容器的支持,跟容器的处理性能有关。
比如Tomcat,没有限制,可以通过配置文件。
server.xml <Connector port="8080" maxPostSize="0">
4)以前的表单只有两个属性 action method=“post”
如果想要做文件上传 表单中必须再添加一个属性
enctype="multipart/form-date"
5)必须使用<input type="file">通过这个组件让用户选择上传的文件,不仅仅能得到文件名,将文件的内容读出来。

服务器端:

1)引入文件上传需要的jar包。
commons-fileupload-1.4.jar
commons-io-2.6.jar
2)使用一个DiskFileItemFactory对象
DiskFileItemFactory factory = new DiskFileItemFactory();
使用一个ServletFileUpload对象,包含一个factory
ServletFileUpload upload = new ServletFileUpload(factory);
使用upload对象解析request ,得到一个List<FileItem>
List<FileItem> itemList = upload.parseRequest(request);
3.自己的业务逻辑
通过遍历集合可以获取每一个item元素,
FileItem item 元素可能是一个普通组件,可能是一个文件
item.isFormField();方法可以判断是否是一个普通文件
如果item是一个普通的组件
注意:不能用原生的方式获取参数request.getParameter();
使用如下方式获取
String = item.getFieldName();获取组件的name属性
String = item.getString();获取组件的value属性
注意:不能使用原生的方式处理中文request.setCharacterEncoding();
使用如下方式处理:item.getString("UTF-8");
如果item判断后是一个文件:
先读取文件的内容:item.getInputStream();
然后将文件用输出流写出:item.write(File file);
4.如果上传的文件较大,可能会报错。因而需要产生临时文件,为了防止丢包。
默认情况下存在tomcat的temp文件夹中。
以下的两种方法可以设置缓冲区大小以及位置:
factory.setSizeThreshold(1024000);//设置缓冲区大小,默认大小为10240
factory.setRpository(new File("路径"));//设置缓冲区位置
还可以设置上传本身的大小:
upload.setFileSizeMax();//限制单个上传文件大小
upload.setSizeMax();//限制上传文件的总大小

举个小例子:

//index.jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
   <form action="saveFile" method="post" enctype="multipart/form-data">
     请输入名字:<input type="text" name="username" value=""><br>
     请选择文件:<input type="file" name="filename" value=""><br>
     <input type="submit" value="确定">
   </form>
  </body>
</html>

  // 配置信息
    <servlet>
        <servlet-name>servlet</servlet-name>
        <servlet-class>controller.Upload</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>servlet</servlet-name>
        <url-pattern>/saveFile</url-pattern>
    </servlet-mapping>
//服务器的上传
package controller;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Upload extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            //创建一个工厂
            DiskFileItemFactory factory = new DiskFileItemFactory();
            //创建ServletFileUpload文件上传
            ServletFileUpload upload = new ServletFileUpload(factory);
            //通过upload解析request对象

            //实现上传文件的监督
            upload.setProgressListener(new ProgressListener() {
                @Override
                public void update(long l, long l1, int i) {
                    //第一个参数表示 已经上传的字节个数,一般以4096个字节查看一下
                    //第二个参数表示 上传文件的总字节数
                    //第三个参数表示 正在上传的第几个组件
                    System.out.println("正在上传第"+i+"个组件,已经上传"+((((double)l/(double)l1)*100))+"%");
                    try{
                        Thread.sleep(300);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            });

            List<FileItem> items = upload.parseRequest(request);
            //将items中所有的item元素遍历
            for (FileItem item : items){
                if (item.isFormField()){//判断是普通的组件
                    String key = item.getFieldName(); //获取key/name
                    String value = item.getString();//获取value
                    System.out.println(key+"---"+value);
                }else {//表示文件
                    String key = item.getFieldName();//接收文件的key
                    String realFileName = item.getName();//接收文件的真实名字
                    //处理中文名乱码的问题
                    item.getString("UTF-8");
                    request.setCharacterEncoding("UTF-8");
                    System.out.println(key+"--"+realFileName);
                    //如何获取根目录?
                    //this.getServletContext().getRealPath("/");
                    //获取一个输入流,读取网络传递过来的文件内容
                    //InputStream inputStream = item.getInputStream();
                    item.write(new File("D://test/"+realFileName));//将文件的内容写在D盘里面
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //设计一个方法,限制上传类型
    private boolean testFileType(String fileName){
        String[] box ={"txt","doc","pdf","jpg","png"};
        //循环遍历数组
        for (int i=0 ; i<box.length ; i++){
            if (fileName.endsWith(box[i])){
                return true;
            }
        }
            return false;
    }


}

总结
文件上传需要注意的事情:

1、浏览器端需要满足的条件:form表单、post请求、enctype属性、file组件(多个)。
2、服务器端需要满足的条件:factory工厂对象、upload对象,解析request方法、list<Filelt>
3、上传文件保存的路径:放在一个固定的位置比如D://test,可移植性不好。放在当前工程的根目录下:String path = this.getServletContext().getRealPath("/");//根目录
4、最好限制一下文件上传的大小:单个、总体、缓冲区。
5、如果文件上传出现文件名冲突的问题?怎么解决?
(1)原来的名字+用户+时间.原来的后缀
比如:1_zzt_date.jpg
(2)用一个随机产生的名字当做保存在服务器中的文件名。
比如:1.jpg—>xxx.jpg
6、有些时候可能上传的文件需要控制类型。
可以自己设计一个方法。

比如:

private boolean testFileType(String fileName){
        String[] box ={"txt","doc","pdf","jpg","png"};
        //循环遍历数组
        for (int i=0 ; i<box.length ; i++){
            if (fileName.endsWith(box[i])){
                return true;
            }
        }
            return false;
    }

4.上传文件知识的补充
实现上传的同时监督一下进度:
upload对象

//实现上传文件的监督
            upload.setProgressListener(new ProgressListener() {
                @Override
                public void update(long l, long l1, int i) {
                    //第一个参数表示 已经上传的字节个数,一般以4096个字节查看一下
                    //第二个参数表示 上传文件的总字节数
                    //第三个参数表示 正在上传的第几个组件
                    System.out.println("正在上传第"+i+"个组件,已经上传"+((((double)l/(double)l1)*100))+"%");
                    try{
                        Thread.sleep(300);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            });

二、文件下载(举小例子说明)

1、浏览器端
需要有个下载按钮。
比如:

<a href="download?fileName=xxx.txt">下载</a>

2、服务器端
1.获取传递过来的文件名字
2.找到该文件,并且读取该文件。
3.如果文件名中含有中文,处理一下字符集
4.设置响应的内容类型。
5.将内容响应回浏览器。

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取传递过来的文件名字
        String fileName = request.getParameter("fileName");
        //2.找到该文件并读取该内容
        InputStream inputStream = new FileInputStream("D://test/"+fileName);
        //3.如果含有中文,就处理一下字符集
        fileName = URLEncoder.encode(fileName,"UTF-8");
        //4.设置响应的contentType内容类型
        response.setContentType("application/x-msdownload");
        response.setHeader("Content-disposition","attachment;filename="+fileName);
        //5.将内容响应回浏览器
        OutputStream outputStream = response.getOutputStream();
        byte[] b = new byte[1024];
        int length = inputStream.read(b);
        while (length != -1){
            outputStream.write(b,0,length);
            outputStream.flush();
            length = inputStream.read();
        }
    }

留言:欢迎各位小伙伴们的评论哈 ~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李宸净

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值