文件上传和下载

发布时间 2023-03-31 22:14:31作者: xiuqizhiping1034

文件上传和下载

使用输入流 用java 的方式从外接读入数据,并在idea中展示图片[展示结果为字符乱码,相当于另一种展示形式]

基本步骤

jsp

  1. input 的type 设置为file形式
  2. form表单的method 设置为post get 请求会将文件名传给服务端,而不是文件本身
  3. form 表单的enctype 设置为 multipart/form-data, 以二进制的形式传输数据

展示结果: 在源码模式下 可以看到文件的大小 以及enctype的设置结果

image-20230329090834510

这里传输的方式和文件大小 对应测试的文件大小和方式[可以在客户端界面进行查看]

<%--
  Created by IntelliJ IDEA.
  User: Lenovo
  Date: 2023/3/28
  Time: 21:55
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form enctype="multipart/form-data" action="/upload" method ="post">
<%--        这里方式选择get 方式只会将文件名字进行传输给后端,所以选择 post方式 --%>

        <input name = "img" type="file"/><br/>
        <input type="submit" value="上传"/>
    </form>
</body>
</html>

Servlet进行接收数据

使用inputStream()流的方式进行读取数据

使用input流的方式 将数据进行读取并展示

package com.southwind.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;

@WebServlet("/upload")
public class uploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
//        下边两行默认是以文本的形式进行读取的,而传输的时候使用的是二进制流的方式进行存储,所以应该改成
//        使用二进制流方式进行读取
        String img = req.getParameter("img");
        System.out.println(img);
*/
//        使用二进制流的方式进行读取
        InputStream inputStream = req.getInputStream();
//        对于后端来说  客户端传过来的数据是输入流,所以是inputStream
//        使用输入流进行处理,借助req 的getInputStream

//        下边使用循环的方式读取io流
        int temp = 0;
        while((temp = inputStream.read())!= -1){//读取到最后一个数据
            System.out.println(temp);
        }

    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

	
    }
}

image-20230329091720909

数据上传并存储在本地

输入流数据上传

后端展示的数据格式:

  1. 固定的浏览器(自带的)加入到数据流中的开头和结尾
  2. 对应的唯一文件的内容

【文本和图片 对应的中间的内容不同,开头和结尾相同】

image-20230329095242662

字节流==> 字符流 ==>Buffer流

一个字节一个字节读,可能两个字节构成一个字符 ==> 字符流是一个字符一个字符直接读取 ==> buffer流一行字符一行字符去读取数据

image-20230329095538371

展示结果 为什么开头是6个45 转换过来 是6个横线,所以是6个45

package com.southwind.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;

@WebServlet("/upload")
public class uploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
//        下边两行默认是以文本的形式进行读取的,而传输的时候使用的是二进制流的方式进行存储,所以应该改成
//        使用二进制流方式进行读取
        String img = req.getParameter("img");
        System.out.println(img);
*/

//        使用二进制流的方式进行读取
/*
        InputStream inputStream = req.getInputStream();
//        对于后端来说  客户端传过来的数据是输入流,所以是inputStream
//        使用输入流进行处理,借助req 的getInputStream

//        下边使用循环的方式读取io流
        int temp = 0;
        while((temp = inputStream.read())!= -1){//读取到最后一个数据
            System.out.println(temp);
        }
*/

//使用输入流+缓冲区 来快速读取数据
        InputStream inputStream = req.getInputStream();
        Reader reader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(reader);
        String str = "";

//        循环在控制台将数据打印
        while((str = bufferedReader.readLine())!= null){
            System.out.println(str);

        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


    }
}

读取出来的文本文档结果

image-20230329095920361

数据输出流保存在服务器项目本地

使用输入流将数据在前端传过来之后,将数据展示出来并使用输出流将数据存储在项目本地

获取输出路径

先创建一个输出路径的file文件,设定输出路径【使用getServletContext的getRealPath()输出路径获取路径】

String path = req.getServletContext().getRealPath("file");

image-20230330162827116

实际的逻辑解析

image-20230330204048707

客户端传过来数据,服务端读取一行,然后在本地文件中写入一行,然后不断循环

//使用输入流+缓冲区 来快速读取数据
        InputStream inputStream = req.getInputStream();
        Reader reader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(reader);
        //使用输出流将数据输出到服务器本地硬盘
        // 获取存储的文件夹的绝对路径[通过Servlet的context 获取上下文对象]
//            使用file文件夹存放服务器项目位置
        String path = req.getServletContext().getRealPath("file/copy.txt");
//              设定输出路径  将结果输出到路径中的某个txt文件 从而实现上传结果保存

//        设定输出流  输出流直接对接path路径
        OutputStream outputStream = new FileOutputStream(path);
//把输出字节流转换成输出字符流 并转换成安行输入
        Writer writer   = new OutputStreamWriter(outputStream);
        BufferedWriter bufferedWriter = new BufferedWriter(writer);

        String str = "";
    //        循环在控制台将数据打印
//        下边使用BufferReader 读进来,在用BufferWriter 写入到本地文件中
        while((str = bufferedReader.readLine())!= null){
//            System.out.println(str);
            bufferedWriter.write(str);
        }
        bufferedWriter.close();
        writer.close();
        outputStream.close();
        bufferedReader.close();
        reader.close();
        inputStream.close();

    }

问题:

  1. 以数据流的方式读入的话,是没有换行符的
  2. 浏览器一些默认的一些信息,被添加在文件中

使用组价开发

fileupload组件

fileupload组件可以将所有的请求信息都解析成Fileltem对象,可以通过对Fileltem对象的操作完成数据上传,是使用的面向对象的思想

image-20230330213715718

借用FileItem方法 将数据流信息转换成对象,然后放入到key value集合中,方便后续进行使用【这里进行展示】

System.out.println(fileItem.getName());//输出对象的name 也就是对应的文件名
System.out.println(fileItem.getFieldName());//fileItem 对应的是输入框的input名

image-20230330214452632

image-20230330214441452

上传两个文件,区分转换后的fileItem对象的name值

getName 对应的是文件的名字

getFileName 对应的是文件的input输入框的名字

帮助直接实现数据 上传和处理

一个文本框 也可以是一个抽象好的文件对象,也可以被获取,并展示name,只不过在调用getFileName()的时候,文件名字为NULL

image-20230331205805654

image-20230331205821764

<%--
  Created by IntelliJ IDEA.
  User: Lenovo
  Date: 2023/3/28
  Time: 21:55
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form enctype="multipart/form-data" action="/upload" method ="post">
<%--        这里方式选择get 方式只会将文件名字进行传输给后端,所以选择 post方式 --%>

        <input name = "desc1" type="text"/><br/>
        <input name = "img" type="file"/><br/>
<%--一个des 表示一个输入框 用来描述对应的文件类型--%>
        <input name = "desc2" type="text"/><br/>
        <input name = "text" type="file"/><br/>
<%--    同时上传两个文件 在FileItem中进行区分FileItem的getFilename 和 getName 方法--%>
        <input type="submit" value="上传"/>
    </form>
</body>
</html>

        try {
            DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();//工厂模式
            ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);// 通过工厂拿到一个Servlet对象
//        通过servletFileUpload对象去解析请求
//        数据流都在请求中,不需要手动去取出请求数据,直接调用下边的servletFileUpload对象方法解析请求获取请求集合
            List<FileItem> list = servletFileUpload.parseRequest(req);
//            把数据流转换成一个FileItem 集合
//            System.out.println(list);  输出存储对象的集合
            for(FileItem fileItem:list){
//                这里一个filename 对应一个input输入框
                System.out.println(fileItem.getName());//输出对象的name 也就是对应的文件名
                System.out.println(fileItem.getFieldName());//fileItem 对应的是输入框的input名

            }

判定并写入本地

判定 是输入框 还是一个文件的方法: fileItem.isFormField() 结果为true 则为文本框,可以在程序中输出内容

为false 则是文件,将文件内容先读入到缓冲区,并将内容写入本地项目

输入输出流的方式进行文本文件和图片的上传
        try {
            DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();//工厂模式
            ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);// 通过工厂拿到一个Servlet对象
//        通过servletFileUpload对象去解析请求
//        数据流都在请求中,不需要手动去取出请求数据,直接调用下边的servletFileUpload对象方法解析请求获取请求集合
            List<FileItem> list = servletFileUpload.parseRequest(req);
//            把数据流转换成一个FileItem 集合
//            System.out.println(list);  输出存储对象的集合
            for(FileItem fileItem:list){
    //使用组件能够去除空行
//                这里一个filename 对应一个input输入框
                System.out.println(fileItem.getName());//输出对象的name 也就是对应的文件名
                System.out.println(fileItem.getFieldName());//fileItem 对应的是输入框的input名

                if(fileItem.isFormField()){//是一个文本框
                    String name = fileItem.getFieldName();//获取框的input名字
                    String value = fileItem.getString("UTF-8");//获取文本框中的值并以utf-8的方式存储
                    System.out.println(name+":"+value);
                }else{//是一个文件
                    String fileName = fileItem.getName();//文件名
                    long size = fileItem.getSize();//文件大小
                    System.out.println(fileName+"的大小是:"+size);
                    InputStream inputStream = fileItem.getInputStream();
                    String path = req.getServletContext().getRealPath("file/"+fileName);//直接将获取的文件名存入到服务器的路径中
                    OutputStream outputStream = new FileOutputStream(path);//设定输出流  字节流传输

                    int temp =0;
                    while((temp = inputStream.read()) != -1){
                        outputStream.write(temp);
                    }
                    outputStream.close();
                    inputStream.close();
                    System.out.println("上传成功");

                }

            }

        } catch (FileUploadException e) {
            e.printStackTrace();
        }

image-20230331211902218

image-20230331211915826

使用字符流上传文本文件和图片

// 图片用字符流上传会无法访问

待测试// 使用整行读取,无法读出换行?因为将两个段落看为一个整体,一直读到最后,有进行下一个整体,换行被忽略??

image-20230331214035665

文件下载

设定浏览器的默认下载器,并先将需要下载的文件放到out中对应的file中去,并设定好路径,然后将数据从路径中读入字节流,并一边读入,一边写出给相应resp的输出区

package com.southwind.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

@WebServlet("/download")
public class FileDownLoadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置相应方式,直接调用浏览器的下载器下载传过去的文件
        resp.setContentType("application/x-msdownload");
        String filename = "11111.png";
        //设置下载后的文件名
        resp.setHeader("Content-Disposition","attachment;filename="+filename);
//        上一行前边都是写死的,只需要改一下文件名即可
        //获取输出流,用相应的方式返回输出流
        OutputStream outputStream = resp.getOutputStream();
        String path = req.getServletContext().getRealPath("file/11111.png");
        InputStream inputStream = new FileInputStream(path);//设定输入流的读取文件路径,从path读取数据
        int temp = 0;
        while((temp=inputStream.read())!=-1){
            outputStream.write(temp);
        }
        inputStream.close();
        outputStream.close();

    }
}
<%--
  Created by IntelliJ IDEA.
  User: Lenovo
  Date: 2023/3/31
  Time: 21:28
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件下载实现</title>
</head>
<body>
    <a href="/download">图片.png</a>
</body>
</html>