热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

java文件上传技术深入剖析

这篇文章主要为大家详细介绍了java文件上传技术深入剖析,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了java文件上传技术,供大家参考,具体内容如下

这里写图片描述

表单:
客户端发送HTTP必须使用multipart/form-data数据类型,表示复合数据类型。即:
在表单中使用html标签。

需要的包:
        Commons-fileupload.jar,核心上传文件工具都在这个包中。
        commons-io.jar – 上传文件所需要的包

上传文件类详解:
DiskFileItemFactory-创建监时文件目录,指是缓存区大小
ServletFileUpload用于解析HttpServletRequest。返回一组文件对象。
FileItem – 表示用户上传的每一个文件对像。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>



 

  
 

 
  过渡板--了解底层
  
  /upload0" method="post" enctype="multipart/form-data">
    文件:
     
      
  
  
使用apache文件上传工具实现文件上传 /upload" method="post" enctype="multipart/form-data"> 文件: 使用apache文件上传工具实现文件上传2(解决文件名乱码)

POST1(普通表单):enctype=application/x-www-form-urlencoded(默认值)

POST2(上传文件表单):enctype=multipart/form-data:多部分(不但有文件,也有部分)

/upload2" method="post" enctype="multipart/form-data"> 文件:
文件说明:

文件2:
文件说明2: 使用apache文件上传工具实现文件上传3(文件打散) /upload3" method="post" enctype="multipart/form-data"> 文件:
文件说明:

文件2:
文件说明2:

这里写图片描述

过渡板–了解底层

package cn.hncu.servlet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Upload0Servlet extends HttpServlet {


  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    InputStream in=request.getInputStream();
    BufferedReader br=new BufferedReader(new InputStreamReader(in));
    String line;
    while((line=br.readLine())!=null){
      System.out.println(line);
    }
  }

}

这里写图片描述

这里写图片描述

使用apache文件上传工具实现文件上传

package cn.hncu.servlet;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;

public class UploadServlet extends HttpServlet {

  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("");
    out.println("");
    out.println(" ");
    out.println(" ");
    out.print("不支持Get方式上传。。。。。。");
    out.println(" ");
    out.println("");
    out.flush();
    out.close();
  }

  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

        //在服务器上,为所有上传文件指定一个存放目录
    String path=getServletContext().getRealPath("/upload");
    System.out.println("path:"+path);
    File dir=new File(path);
    if(!dir.exists()){
      dir.mkdirs();
    }

    //创建一个基于硬盘的工厂
    //DiskFileItemFactory disk = new DiskFileItemFactory();
    //设置临时目录(建议设计临时目录,否则会使用系统临时目录。)
    //disk.setRepository(new File(“d:/a”));
    //3、 设置向硬盘写数据的缓冲区大小
disk.setSizeThreshold(1024*4);//当文件大于此设置时,将会在临时目录下形成临时文件


    //设置临时文件缓冲区大小--8K缓冲,临时文件地址
    DiskFileItemFactory f=new DiskFileItemFactory(1024*8, new File("d:/a"));
    //上传工具--创建用于解析的对像
    ServletFileUpload upload=new ServletFileUpload(f);
    upload.setFileSizeMax(1024*1024*5);//设置上传的单个文件最大为5M
    //设置上传文件的最大大小,如果是多个文件,则为多个文件的和最大8M
    upload.setSizeMax(1024*1024*8);//设置所有上传的文件大小之和最大为8M
    //使用解析工具解析
    try {
      List list=upload.parseRequest(request);
      for(FileItem fI:list){
        System.out.println("文件内容类型:"+fI.getContentType());//文件内容类型:text/plain
        System.out.println("文件名:"+fI.getName());//文件名:C:\Users\adl1\Desktop\a.txt
        String ext=fI.getName().substring(fI.getName().lastIndexOf("."));//.txt
        String uuid=UUID.randomUUID().toString().replace("-", "");
        String fileName=uuid+ext;
//       FileUtils.copyInputStreamToFile(fI.getInputStream(), new File("d:/a/d/a.txt"));//写死了
        //fI.getInputStream()是真正文件信息
        FileUtils.copyInputStreamToFile(fI.getInputStream(), new File(path+"/"+fileName));//写活了
      }
    } catch (FileUploadException e) {
      e.printStackTrace();
    }


  }

}

在这个地方存储上传的文件

这里写图片描述

上传信息:

这里写图片描述

上传结果:

这里写图片描述

使用apache文件上传工具实现文件上传2(解决文件名乱码)

package cn.hncu.servlet;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;

public class Upload2Servlet extends HttpServlet {

  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {


    response.setContentType("text/html");
    //如果是含上传文件的表单(POST2),该剧只能设置所上传文件的文件名中的编码(解决他的中文乱码)
    //但不能解决在POST2方式下的普通表单组件的中文乱码
    PrintWriter out = response.getWriter();
    out.println("");
    out.println("");
    out.println(" ");
    out.println(" ");
    out.print("不支持Get方式上传。。。。。。");
    out.println(" ");
    out.println("");
    out.flush();
    out.close();
  }

  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    //第一步
    //普通的form表单(POST1),下面这句可以设置普通表单组件内容的编码(能够解决它们的中文乱码问题)
    request.setCharacterEncoding("utf-8");
    //如果是含上传文件的表单(POST2),该句只能设置所上传文件的文件名中的编码(解决它的中文乱码)。但不能解决普通表单组件的乱码(不能设它编码)


    //在服务器上,为所有上传文件指定一个存放目录
    String path=getServletContext().getRealPath("/upload");
    System.out.println("path:"+path);
    File dir=new File(path);
    if(!dir.exists()){
      dir.mkdirs();
    }


    //设置临时文件缓冲区大小--8K缓冲,临时文件地址
    DiskFileItemFactory f=new DiskFileItemFactory(1024*8, new File("d:/a"));
    //上传工具
    ServletFileUpload upload=new ServletFileUpload(f);
    upload.setFileSizeMax(1024*1024*5);//设置上传的单个文件最大为5M
    upload.setSizeMax(1024*1024*8);//设置所有上传的文件大小之和最大为8M
    //使用解析工具解析
    try {
      List list=upload.parseRequest(request);
      for(FileItem fI:list){
        if((fI.isFormField())){//如果是普通表单组件:checkbox,radio,password...
//         String desc=fI.getString();
          System.out.println("fI.getString():"+fI.getString());
          //第二步
          String desc=fI.getString("utf-8");
          //该句设置普通表单组件内容编码
          System.out.println("编码后:"+desc);
        }else{
          String ext=fI.getName().substring(fI.getName().lastIndexOf("."));//.txt
          String uuid=UUID.randomUUID().toString().replace("-", "");
          String fileName=uuid+ext;
          //fI.getInputStream()是真正文件信息
          FileUtils.copyInputStreamToFile(fI.getInputStream(), new File(path+"/"+fileName));//写活了
        }
      }
    } catch (FileUploadException e) {
      e.printStackTrace();
    }
  }
}

上传信息:

这里写图片描述

上传结果:
这里写图片描述 

使用apache文件上传工具实现文件上传3(文件打散)

用Hash目录优化文件存储:
Hash目录是一种优化文件存储性能的方法。无论是Windows还是Linux,无论是NTFS还是ext3,每个目录下所能容纳的项目数是有限的。
并不是不能保存,而是当项目数量过大的时候,会降低文件索引速度,
所以权衡一个目录下应该保存多少文件是很必要的。保存得多了会影响性能,保存得少了会造成目录太多和空间浪费。所以当保存大批文件的时候,
需要有一种算法能将文件比较均匀地“打散”在不同的子目录下以提高每一级的索引速度,这种算法就是 Hash。通常用的MD5、sha1等都可以用来做Hash目录,我的Session里也同样使用了MD5,取得sessionID的第一位和第九位,这就构成了两级Hash路径,也就是说,系统把所有的Session文件分散到了16×16=256个子目录下。假设Linux每个目录下保存1000个文件可以获得最好的空间性能比,那么系统在理想情况下可以同时有256000个session文件在被使用。

package cn.hncu.servlet;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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 org.apache.commons.io.FileUtils;

public class Upload3Servlet extends HttpServlet {

  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {


    response.setContentType("text/html");
    //如果是含上传文件的表单(POST2),该剧只能设置所上传文件的文件名中的编码(解决他的中文乱码)
    //但不能解决在POST2方式下的普通表单组件的中文乱码
    PrintWriter out = response.getWriter();
    out.println("");
    out.println("");
    out.println(" ");
    out.println(" ");
    //获取GET方式的url中“&#63;”号后面的部分
    //http://localhost:8080/servletDemo3/upload&#63;name=Jack&sex=male
    String qStr = request.getQueryString();
    System.out.println("qStr: "+qStr);//qStr: name=Jack&sex=male
    out.print("不支持Get方式上传。。。。。。");
    out.println(" ");
    out.println("");
    out.flush();
    out.close();
  }

  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    response.setContentType("text/html;charset=utf-8");
    PrintWriter out = response.getWriter();
    //1防黑: 防护前端采用POST1方式提交
    //法1
    /*
    String type=request.getContentType();
    if(!type.contains("multipart/form-data")){
      out.println("不支持普通表单提交");
      return;
    }*/
    //法2
    boolean boo = ServletFileUpload.isMultipartContent(request);
    if(!boo){
      out.println("不支持普通表单提交");
      return;
    }

    //第一步
    //普通的form表单(POST1),下面这句可以设置普通表单组件内容的编码(能够解决它们的中文乱码问题)
    request.setCharacterEncoding("utf-8");
    //如果是含上传文件的表单(POST2),该句只能设置所上传文件的文件名中的编码(解决它的中文乱码)。但不能解决普通表单组件的乱码(不能设它编码)


    //在服务器上,为所有上传文件指定一个存放目录
    String path=getServletContext().getRealPath("/upload");
    System.out.println("path:"+path);
    File dir=new File(path);
    if(!dir.exists()){
      dir.mkdirs();
    }


    //设置临时文件缓冲区大小--8K缓冲,临时文件地址
    DiskFileItemFactory f=new DiskFileItemFactory(1024*8, new File("d:/a"));
    //上传工具
    ServletFileUpload upload=new ServletFileUpload(f);
    upload.setFileSizeMax(1024*1024*5);//设置上传的单个文件最大为5M
    upload.setSizeMax(1024*1024*8);//设置所有上传的文件大小之和最大为8M

    //▲4上传进度监听
    upload.setProgressListener(new ProgressListener(){
      private double pre=0D;
      @Override//参数1:已上传多少字节 参数2:一共多少字节  参数3:第几个文件(序号从1开始)
      public void update(long pByteRead, long pContentLength, int pItems) {
        double d = 1.0*pByteRead/pContentLength*100;
        System.out.println(d+"%");
            if(pre!=d){
              System.out.println(d+"%");
              pre=d;
            }
      }
    });


    //使用解析工具解析
    try {
      List list=upload.parseRequest(request);
      for(FileItem fI:list){
        if((fI.isFormField())){//如果是普通表单组件:checkbox,radio,password...
//         String desc=fI.getString();
          System.out.println("fI.getString():"+fI.getString());
          //第二步
          String desc=fI.getString("utf-8");
          //该句设置普通表单组件内容编码
          System.out.println("编码后:"+desc);
        }else{
          //防护:过滤掉没选择文件的空文件组件
          if(fI.getSize()<=0){
            continue;//读下一个文件
          }

          System.out.println("文件内容类型:"+fI.getContentType());//文件内容类型:text/plain
          System.out.println("文件名:"+fI.getName());//文件名:C:\Users\adl1\Desktop\a.txt

          String ext=fI.getName().substring(fI.getName().lastIndexOf("."));//.txt
          String uuid=UUID.randomUUID().toString().replace("-", "");
          String fileName=uuid+ext;

          //文件目录打散技术
          String dir1=Integer.toHexString(uuid.hashCode()&0x0f);
          String dir2=Integer.toHexString((uuid.hashCode()&0xf0)>>4);


          //fI.getInputStream()是真正文件信息
          FileUtils.copyInputStreamToFile(fI.getInputStream(), new File(path+"/"+dir1+"/"+dir2+"/"+fileName));//写活了
        }
      }
    } catch (FileUploadException e) {
      e.printStackTrace();
    }
  }
}

打散信息:

这里写图片描述

打散结果:

文件1:

这里写图片描述 

文件2:

这里写图片描述

演示上传进度原理

这里写图片描述

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • Webmin远程命令执行漏洞复现及防护方法
    本文介绍了Webmin远程命令执行漏洞CVE-2019-15107的漏洞详情和复现方法,同时提供了防护方法。漏洞存在于Webmin的找回密码页面中,攻击者无需权限即可注入命令并执行任意系统命令。文章还提供了相关参考链接和搭建靶场的步骤。此外,还指出了参考链接中的数据包不准确的问题,并解释了漏洞触发的条件。最后,给出了防护方法以避免受到该漏洞的攻击。 ... [详细]
  • 阿里Treebased Deep Match(TDM) 学习笔记及技术发展回顾
    本文介绍了阿里Treebased Deep Match(TDM)的学习笔记,同时回顾了工业界技术发展的几代演进。从基于统计的启发式规则方法到基于内积模型的向量检索方法,再到引入复杂深度学习模型的下一代匹配技术。文章详细解释了基于统计的启发式规则方法和基于内积模型的向量检索方法的原理和应用,并介绍了TDM的背景和优势。最后,文章提到了向量距离和基于向量聚类的索引结构对于加速匹配效率的作用。本文对于理解TDM的学习过程和了解匹配技术的发展具有重要意义。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • Linux磁盘的分区、格式化的观察和操作步骤
    本文介绍了如何观察Linux磁盘的分区状态,使用lsblk命令列出系统上的所有磁盘列表,并解释了列表中各个字段的含义。同时,还介绍了使用parted命令列出磁盘的分区表类型和分区信息的方法。在进行磁盘分区操作时,根据分区表类型选择使用fdisk或gdisk命令,并提供了具体的分区步骤。通过本文,读者可以了解到Linux磁盘分区和格式化的基本知识和操作步骤。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
author-avatar
书友71424043
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有