文件上传

一、概述

  1. 在web开发中经常需要从客户端向服务端上传文件 , 如: 照片 、 文件 , 这些通常都需要web开发中的文件上传技术实现。

二、 文件上传开发步骤

  1. 提供一个带有文件上传项的表单

    1. 文件上传的输入框必须有name属性才能被上传
    2. 文件上传的表单必须是Post提交 , 因为Get请求对参数的格式有种种限制如:限制大小为4kb , 只能传输简单字符。。。
    3. 文件上传的表单必须设置enctype=mulipart/form-data
  2. 在servlet中处理文件上传相关的逻辑方案
    1. 方式一 : 可以通过JavaEE原生的API来获取请求中使体内容的流
    2. 获取到流中的数据在进行解析处理
    3. 但是过于繁琐 , 不推荐使用
    4. 方式二: 使用开源工具实现
      1. 使用开源工具实现 Apache提供的文件上传包 – Commons-fileupload
  3. 相关逻辑的开发

    1. 下载并导入对应的包

      1. Commons-fileupload
      2. Commons-io
      3. 扩展: POI Java代码操作office的开源组件
    2. 相关类详解

      1. 文件上传工厂DiskFileItemFactory

        1. public DiskFileItemFactory(int sizeThreshold , java.io.File repository)

          1. sizeTHreshold :指定内存缓冲区大小
          2. repository :指定临时文件存放位置
          3. 注意:
            1. 文件上传时需要将请求的实体内容全部读取后才做处理
            2. 此时需要将实体内容缓冲起来。 内存缓冲快 , 但是内存本身就不大 , 容易导致系统崩溃 。 文件缓冲慢 , 但是可以缓冲大量数据 。
            3. 所以此处提供了两个选项 ,用sizeTHreshold设置内存允许缓冲的最大 数据量 。 如果数据量大于sizeThreshold ,则使用文件缓冲 , 在repository指定的目录下创建临时文件来缓冲 。 如果数据小于sizeThreshold , 则使用内存缓冲
      2. 文件上传的核心类ServletFileUpload
        1. ServletFileUpload sfl = new ServletFileUpload(factory);
        2. boolean isMultipartContent(HttpRequest request)判断当前上传的表单是否是enctype=mulipart/form-data格式
        3. setHeaderEncoding(String encodeing): 指定文件处理时使用的编码
        4. setFileSizeMax(long filesizemax):控制单个文件上传的最大大小值
        5. setSizeMax(long sizeMax):控制总的文件上传的最大值
        6. List parseRequest(HttpServeltRequest request):解析request对象 获取FileItem集合
        7. setProgressListener设置上传文件的监听
      3. 文件上传项 FileItem

        List<FileItem> parseRequest(HttpServeltRequest request)
        
        1. 遍历Item分别做处理
        2. 判断下一个Item是不是一个普通字段
          1. isFormField():如果返回true , 则是普通字段

            1. getFieldName()获取字段名
            2. getString(String encoding):获取字段的值 , 可以再获取字段值得时候设置字段值的编码集
          2. 如果是文件上传项
            1. getName():获取文件名
            2. getInputStream()获取文件流
        3. delete():遍历完之后 记得删除临时文件

三、文件上传时需要注意的点

  1. ie兼容

    1. 当用户使用ie浏览器上传文件时 , 通过getName()获取的是该文件在客户端主机 里的绝对路径 , 而其他浏览器使用getName()时获取的仅仅是文件名 , 在创建目录时我们需要在真实的文件名前添加服务器文件存放的路径 ,所以ie浏览器上传的文件如果不对文件名做处理则会服务器爆出路径无效异常
    2. 处理:

      if(name.contians("\\")){name = name.subString(name.lastIndexOf("\\"));
      }
      
  2. 文件上传保存位置问题
    1. 文件上传保存位置一定不能被 外界随意访问 , 防止用户用浏览器直接访问下载服务器资源 或者执行恶意代码。
    2. WEB-INF目录时不能被外界直接访问的 , 文件上传之后要么保存在WEB-INF目录下 , 要目放置在本地磁盘的其他位置 , 保证浏览无法直接访问 。
  3. 文件上传重名问题
    1. 在同一路径下操作系统不允许文件重名 , 如果有文件重名 ,注入后来的文件会直接覆盖原有的文件 。
    2. 在文件保存时在文件名之前拼接UUID来确保文件名绝对唯一
    3. 扩展:UUID是基于系统时间、CPU时钟等参数使用哈希算法得出的值 , 是永远不会重复的 。
  4. 上传文件保存目录保存文件过多时系统处理困难导致无法读取的情况
    1. 一个文件夹下保存的文件过多时 , 会造成访问缓慢 , 甚至可能造成无法访问的情况 , 所以要想办法将上传的文件分目录存储
    2. 利用hash算法的散列特性
      1. 将带有UUID的文件名根据散列算法得出一个32位的二进制字符串后转为16进制的8位字符
      2. 将得到的8位字符的字符串的每一位截取出来都作为一级路径
      3. 最终文件存放在8级的hash目录下, 一共可能有16^8(42亿多一点)个文件夹分目录来存放文件 , 从而保证了每一个目录都不会存放过多的文件
  5. 示例:

    public class UploadServlet extends HttpServlet {public void doGet(final HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {try {response.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");//1.创建文件上传工厂DiskFileItemFactory factory = new DiskFileItemFactory(100, new File(this.getServletContext().getRealPath("WEB-INF/temp")));//2.创建文件上传的核心类ServletFileUpload fileUpload = new ServletFileUpload(factory);//--判断当前文件上传的表单是否满足enctype=multipart/form-dataif(!fileUpload.isMultipartContent(request)){throw new RuntimeException("请使用正确的文件上传表单上传数据!");}//--设置文件名解析时采用的编码fileUpload.setHeaderEncoding("utf-8");//--单个文件不能超过1MB//fileUpload.setFileSizeMax(1024 * 1024);//--总大小不能超过10MB//fileUpload.setSizeMax(10 * 1024 * 1024);//--设置上传文件的监听fileUpload.setProgressListener(new ProgressListener(){long begin = System.currentTimeMillis();public void update(long pBytesRead, long pContentLength,int pItems) {
    //                  System.out.print("正在读取第"+pItems+"个上传项。。");
    //                  System.out.print("共"+pContentLength+"字节。。");
    //                  System.out.print("已经读取了"+pBytesRead+"字节。。");long leftBytes = pContentLength - pBytesRead;
    //                  System.out.print("剩余"+leftBytes+"字节。。");long now = System.currentTimeMillis();long usetime = (now - begin)/1000 ;
    //                  System.out.print("已经用时" + usetime+"秒。。");long speed = usetime == 0 ? 0 : pBytesRead / usetime / 1024;
    //                  System.out.print("上传速度" + speed+"KB/s。。");double per = Math.round(pBytesRead * 10000.0 / pContentLength)/100.0;System.out.println("上传百分比" + per + "%。。");long lefttime = speed == 0 ? 0 : leftBytes /1024 / speed;
    //                  System.out.println("大致剩余时间"+lefttime+"秒");request.getSession().setAttribute("progress", per);}});//--解析request得到FileItem的集合List<FileItem> items = fileUpload.parseRequest(request);//--遍历每个item分别做处理for(FileItem item : items){if(item.isFormField()){//普通字段项String name = item.getFieldName();String value = item.getString("utf-8");System.out.println(name+"~"+value);}else{//文件上传项String fname = item.getName();//--处理ie文件名bugif(fname.contains("\\")){fname = fname.substring(fname.lastIndexOf("\\")+1);}//--处理文件名 使其不会重复String savename = UUID.randomUUID().toString()+"_"+fname;//--文件分目录处理//----获取文件名的hash 转换为16进制字符串表现形式 由于文件名随机 所以 hash值也是散列的String hash = Integer.toHexString(savename.hashCode());//----如果hash不足8位则在前面拼接足够8位的0while(hash.length()<8){hash += "0";}//----遍历hash值字符串的每一个字符作为一级目录拼接String savepath = "/WEB-INF/upload/";for(int i = 0;i<hash.length();i++){savepath += (hash.charAt(i)+"/");}//----创建出该目录new File(this.getServletContext().getRealPath(savepath)).mkdirs();//----得到输入流InputStream in = item.getInputStream();//----得到输出流 路径就是上面 hash拼接出的路径+文件名OutputStream out = new FileOutputStream(this.getServletContext().getRealPath(savepath + "/" +savename));//----输出数据到文件byte []  data = new byte[1024];int n = -1;while((n = in.read(data))!=-1){out.write(data,0,n);}//----关闭流in.close();out.close();//----删除缓存文件item.delete();}}} catch (FileSizeLimitExceededException e) {response.getWriter().write("文件大小超过限制!!");} catch (Exception e) {throw new RuntimeException(e);}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
    

四、文件上传进度条的实现

  1. 在Upload.jsp页面中 ,为表单提交时间增加函数触发,增加定时器 , 每隔一段时间通过Ajax向服务器发送请求获取最新的上传进度
  2. 在UploadServlet中为文件上传注册监听器 , 计算各种指标 , 存入session中
  3. 在UploadProgressServlet中从session中获取上传进度信息 , 作为响应发回给Ajax后设置进度条长度。

大数据WE阶段(十七)文件上传相关推荐

  1. 大数据之 将txt文件上传到HDFS并用Hive查询

    在生产上,一般对数据清洗之后直接放到HDFS上,再将目录加载到分区表中,之后通过hive去查询分析数据: 1.准备数据 order_created.txt 用 tab分割 10703007267488 ...

  2. spring boot 整合web开发之文件上传、静态资源访问、异常处理、返回JSON数据

    目录 springboot 整合web开发 返回json数据 静态资源访问 文件上传 全局异常 1.返回json数据 springboot默认的是jackson-databind做为json处理器.也 ...

  3. 前端大文件上传和下载(分片上传)

    前端大文件上传和下载(分片上传) 一.问题 日常业务中难免出现前端需要向后端传输大型文件的情况,这时单次的请求不能满足传输大文件的需求,就需要用到分片上传 业务需求为:用户可以上传小于20G的镜像文件 ...

  4. 网安基础学习之“文件上传漏洞原理与实现”

    网安基础学习之"文件上传漏洞原理与实现" 近期新闻头条上报出了"长沙市场监管局网站被上传了黄色页面",经过长沙市公安局网技支队的排查,该门户网站后台编辑器存在* ...

  5. javaWeb实现文件上传与下载 (转)

    文件上传概述 实现web开发中的文件上传功能,需完成如下二步操作: 在web页面中添加上传输入项 在servlet中读取上传文件的数据,并保存到本地硬盘中. 如何在web页面中添加上传输入项? < ...

  6. Alamofire4.x开源代码分析(三)文件上传下载

    2019独角兽企业重金招聘Python工程师标准>>> Alamofire支持下载图片到内存或者磁盘,Alamofire.request开头的请求会把数据加载进内存,适用于小文件,如 ...

  7. Javaweb_文件上传

    多看视频,自己看一遍代码,跑一遍代码,最后跟着老师的思路在理一理,最主要就学会使用! [狂神说Java]JavaWeb入门到实战_文件上传 目录 文件下载:HttpServletResponse可以实 ...

  8. uploader.lib php,Fine Uploader文件上传组件应用介绍

    最近在处理后台数据时需要实现文件上传.考虑到对浏览器适配上采用Fine Uploader. Fine Uploader 采用ajax方式实现对文件上传.同时在浏览器中直接支持文件拖拽[对浏览器版本有要 ...

  9. ftp 服务器 单文件上传,ftp 服务器 单文件上传

    ftp 服务器 单文件上传 内容精选 换一换 本文介绍如何在 Linux 系统的本地机器上使用 FTP 服务,将文件从本地上传到云服务器中.已在待上传文件的云服务器中搭建 FTP 服务.如果您的云服务 ...

  10. django文件上传到服务器,django上传文件的三种方式

    Django文件上传需要考虑的重要事项 文件或图片一般通过表单进行.用户在前端点击文件上传,然后以POST方式将数据和文件提交到服务器.服务器在接收到POST请求后需要将其存储在服务器上的某个地方.D ...

最新文章

  1. java类型转换面试题_JavaSE:数据类型之间的转换(附常见面试题)
  2. IP地址不够了,有办法吗?
  3. 【Verilog HDL 训练】第 06 天(边沿检测)
  4. python matplotlib画图的几个实例--latex,坐标系等
  5. 用什么方式链接oracle数据库,使用cx_Oracle 连接oracle数据库的几种方式
  6. HiveSQL运行优化参数配置
  7. sap中用函数增加断点(break point)
  8. 十、eclipse快捷键大全
  9. C++之关于初始化列表(Initialization List)的一个补充示例
  10. python123程序设计题答案第三周_Python 3 程序设计学习指导与习题解答
  11. 英语语法总结--独立主格
  12. 前端面试题和setTimeout异步
  13. python 科大讯飞 语音转文字 输出干活
  14. android 高仿网易,Android项目实战教程之高仿网易云音乐启动页实例代码
  15. TM4C123G学习记录(4)--关于ROM前缀函数和HWREG函数
  16. android11 动态设置屏幕旋转方向
  17. canvas教程2-canvas的编程思想
  18. 踱步狼注释移除状态机算法2019.10
  19. 【蓝桥杯国赛真题08】python约分 蓝桥杯青少年组python编程 蓝桥杯国赛真题解析
  20. 历史性一刻,中国航天器首次登上火星!!!

热门文章

  1. JavaScript之childNodes属性、nodeType属性学习
  2. 【原】动态申请二维数组并释放的三种方法
  3. callback回调使用 vue_前端动画必知必会:React 和 Vue 都在用的 FLIP 思想实战
  4. 华为鸿蒙系统首发设备,华为鸿蒙系统首发设备曝光!不是手机
  5. css 样式三元运算_20条书写CSS代码的建议
  6. aliplayer 手机全屏控件不显示_Flutter 强大的MediaQuery控件
  7. Halcon - 定位 - 卡尺
  8. Nginx技术研究系列7-Azure环境中Nginx高可用性和部署架构设计
  9. oracle 11g安装教程
  10. mysql中union与union all的区别