一、 文件上传
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();
}
}
留言:欢迎各位小伙伴们的评论哈 ~