文件上传和下载
文件上传和下载
使用输入流 用java 的方式从外接读入数据,并在idea中展示图片[展示结果为字符乱码,相当于另一种展示形式]
基本步骤
jsp
- input 的type 设置为file形式
- form表单的method 设置为post get 请求会将文件名传给服务端,而不是文件本身
- form 表单的enctype 设置为 multipart/form-data, 以二进制的形式传输数据
展示结果: 在源码模式下 可以看到文件的大小 以及enctype的设置结果
这里传输的方式和文件大小 对应测试的文件大小和方式[可以在客户端界面进行查看]
<%--
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 {
}
}
数据上传并存储在本地
输入流数据上传
后端展示的数据格式:
- 固定的浏览器(自带的)加入到数据流中的开头和结尾
- 对应的唯一文件的内容
【文本和图片 对应的中间的内容不同,开头和结尾相同】
字节流==> 字符流 ==>Buffer流
一个字节一个字节读,可能两个字节构成一个字符 ==> 字符流是一个字符一个字符直接读取 ==> buffer流一行字符一行字符去读取数据
展示结果 为什么开头是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 {
}
}
读取出来的文本文档结果
数据输出流保存在服务器项目本地
使用输入流将数据在前端传过来之后,将数据展示出来并使用输出流将数据存储在项目本地
获取输出路径
先创建一个输出路径的file文件,设定输出路径【使用getServletContext的getRealPath()输出路径获取路径】
String path = req.getServletContext().getRealPath("file");
实际的逻辑解析
客户端传过来数据,服务端读取一行,然后在本地文件中写入一行,然后不断循环
//使用输入流+缓冲区 来快速读取数据
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();
}
问题:
- 以数据流的方式读入的话,是没有换行符的
- 浏览器一些默认的一些信息,被添加在文件中
使用组价开发
fileupload组件
fileupload组件可以将所有的请求信息都解析成Fileltem对象,可以通过对Fileltem对象的操作完成数据上传,是使用的面向对象的思想
借用FileItem方法 将数据流信息转换成对象,然后放入到key value集合中,方便后续进行使用【这里进行展示】
System.out.println(fileItem.getName());//输出对象的name 也就是对应的文件名
System.out.println(fileItem.getFieldName());//fileItem 对应的是输入框的input名
上传两个文件,区分转换后的fileItem对象的name值
getName 对应的是文件的名字
getFileName 对应的是文件的input输入框的名字
帮助直接实现数据 上传和处理
一个文本框 也可以是一个抽象好的文件对象,也可以被获取,并展示name,只不过在调用getFileName()的时候,文件名字为NULL
<%--
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();
}
使用字符流上传文本文件和图片
// 图片用字符流上传会无法访问
待测试// 使用整行读取,无法读出换行?因为将两个段落看为一个整体,一直读到最后,有进行下一个整体,换行被忽略??
文件下载
设定浏览器的默认下载器,并先将需要下载的文件放到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>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人