浅谈文件的上传与下载

01_文件上传

本质就是将一台电脑中的文件根据网络协议通过io流传递到另外一台电脑(服务器)上。
文件上传三要素
表单提交方式为post
表单中需要文件上传项
enctype=multipart/form-data
文件上传代码实现
1,导入jar包
2,文件上传项
3,编写Servlet
创建磁盘文件项工厂对象DiskFileItemFactory
创建核心解析类ServletFileUpload
解析请求,获取到所有的文件项

DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
ServletFileUpload servletFileUpload = new
ServletFileUpload(diskFileItemFactory);
try {
    List<FileItem> fileItems = servletFileUpload.parseRequest(request);
    for (FileItem fileItem : fileItems) {
        if (fileItem.isFormField()){
            String desc = fileItem.getString();
        }else {
            InputStream inputStream = fileItem.getInputStream();
            BufferedInputStream bis = new BufferedInputStream(inputStream);
            String contextPath =
request.getServletContext().getRealPath("upload");
            File contextFile = new File(contextPath);
            if (!contextFile.exists()){
                contextFile.mkdir();
            }
            String path = contextPath+File.separator+fileItem.getName();
            BufferedOutputStream bos = new BufferedOutputStream(new
FileOutputStream(path));
            byte[] bys = new byte[8192];
            int len = ‐1;
            while((len = bis.read(bys)) != ‐1){
                bos.write(bys,0,len);
            }
            bis.close();
            bos.close();
        }
    }
} catch (Exception e) {
	e.printStackTrace();
}

02_文件上传API

ServletFileUpload:核心解析类
parseRequest(HttpServletRequest request):解析请求,并获取相关文件项
setHeaderEncoding(String encoding):解决中文文件名乱码
FileItem:文件项
boolean isFormField()
返回为true,普通字段。返回为false,就是文件。
String getFieldName()
获取表单字段
String getString(String encoding)
根据指定编码格式获取字段值
String getName()
获取上传文件名称
InputStream getInputStream()
获取上传文件对应的输入流
上传文件名称重复问题

03_文件上传结合数据库

04_文件下载

本质就是将一台电脑(服务器)中的文件根据网络协议通过io流传递到另外一台电脑上。
文件下载两种形式
1. 超链接

如果浏览器支持这个格式的文件.可以在浏览器中打开.如果浏览器不支持这个格式的文件才会提示下载.

2.手动编写代码的方式下载
手动编写代码实现下载包括:

设置媒体类型
设置下载窗口
开始读写

String fileName = "ceshi.txt";
String realPath = request.getServletContext().getRealPath("/download"+
File.separator+fileName);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath));
//设置媒体类型
response.setContentType(request.getServletContext().getMimeType(fileName));
//设置下载窗口
response.setHeader("Content‐Disposition","attachement;filename="+fileName);
byte[] bys = new byte[8192];
int len = ‐1;
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
//开始读写
while((len = bis.read(bys)) != ‐1){
    bos.write(bys,0,len);
}
bis.close();
bos.close();
解决下载文件名中文乱码问题
设置窗口中的文件名称
String newFileName = null;
String userAgent = request.getHeader("User‐Agent");
if("Chrome".equals(userAgent)){
    //谷歌
    newFileName = URLEncoder.encode(fileName, "utf‐8");
}else {
    newFileName = base64EncodeFileName(fileName);
}
//设置下载窗口
response.setHeader("Content‐Disposition","attachement;filename="+newFileName);
//base64编码
public String base64EncodeFileName(String fileName) {
    BASE64Encoder base64Encoder = new BASE64Encoder();
    try {
        return "=?UTF‐8?B?"
                + new String(base64Encoder.encode(fileName
                .getBytes("UTF‐8"))) + "?=";
    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}

05_自定义文件上传

A.文件上传分析图解
【客户端】输入流,从硬盘读取文件数据到程序中。
【客户端】输出流,写出文件数据到服务端。
【服务端】输入流,读取文件数据到服务端程序。
【服务端】输出流,写出文件数据到服务器硬盘中。
在这里插入图片描述
B.客户端实现

Socket socket = null;
try {
  socket = new Socket(InetAddress.getByName("127.0.0.1"), 6666);
  OutputStream outputStream = socket.getOutputStream();
  BufferedOutputStream bos = new BufferedOutputStream(outputStream);
  BufferedInputStream bis = new BufferedInputStream(new
FileInputStream("C:\\Users\\qiuzhiwei\\Desktop\\a.pptx"));
  byte[] bys = new byte[8192];
  int len = ‐1;
  while ((len = bis.read(bys)) != ‐1) {
    bos.write(bys, 0, len);
  }
  System.out.println("已上传");
} catch (Exception e) {
  e.printStackTrace();
} finally {
  try {
    socket.close();
  } catch (IOException e) {
    e.printStackTrace();
  }
}

C.服务端实现

ServerSocket serverSocket = null;
try {
   serverSocket = new ServerSocket(6666);
  Socket socket = serverSocket.accept();
  InputStream inputStream = socket.getInputStream();
  BufferedInputStream bis = new BufferedInputStream(inputStream);
  BufferedOutputStream bos = new BufferedOutputStream(new
FileOutputStream("C:\\Users\\qiuzhiwei\\Desktop\\copy.pptx"));
  byte[] bys = new byte[8192];
  int len = ‐1;
  while ((len = bis.read(bys)) != ‐1) {
    bos.write(bys, 0, len);
  }
  System.out.println("已保存");
} catch (IOException e) {
  e.printStackTrace();
} finally {
  try {
    serverSocket.close();
  } catch (IOException e) {
    e.printStackTrace();
  }
}

D.优化
a. 文件名称写死的问题
服务端,保存文件的名称如果写死,那么最终导致服务器硬盘,只会保留一个文件,建议使用系统时间优化,保证文件名称唯一,代码如下:
FileOutputStream fis = new FileOutputStream(System.currentTimeMillis()+".jpg") // 文件名称
BufferedOutputStream bos = new BufferedOutputStream(fis);
b. 循环接收的问题
服务端,指保存一个文件就关闭了,之后的用户无法再上传,这是不符合实际的,使用循环改进,可以不断的接收不同用户的文件,代码如下:

// 每次接收新的连接,创建一个Socket
whiletrue{
    Socket accept = serverSocket.accept();
    ......
}
    1. 效率问题
  • 服务端,在接收大文件时,可能耗费几秒钟的时间,此时不能接收其他用户上传,所以,使用多线程技术优化,代码如下:
while(true){
    Socket accept = serverSocket.accept();
    // accept 交给子线程处理.
    new Thread(() ‐> {
       ......
        InputStream bis = accept.getInputStream();
       ......
    }).start();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值