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"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>

  <title>文件上传演示</title>
 </head>

 <body>
  <font color="red" size="6">过渡板--了解底层</font>
  <!-- multipart/form-data:多部分(不但有文件,也有部分) -->
  <form action="<%=request.getContextPath()%>/upload0" method="post" enctype="multipart/form-data">
    文件:<input type="file" name="file"/>
    <input type="submit" value="上传"/>
    <!-- 上传的文件名不能为中文,否则获取的文件名是乱码,不过下面的例子可以解决这个问题 -->
  </form>
  <br/>

  <font color="red" size="6">使用apache文件上传工具实现文件上传</font>
  <!-- application/x-www-form-urlencoded -->
  <form action="<%=request.getContextPath()%>/upload" method="post" enctype="multipart/form-data">
    文件:<input type="file" name="file"/>
    <input type="submit" value="上传"/>
  </form>

  <font color="red" size="6">使用apache文件上传工具实现文件上传2(解决文件名乱码)</font>
  <p>
  POST1(普通表单):enctype=application/x-www-form-urlencoded(默认值)
  </p>
  <p>
  POST2(上传文件表单):enctype=multipart/form-data:多部分(不但有文件,也有部分)
  </p>
  <form action="<%=request.getContextPath()%>/upload2" method="post" enctype="multipart/form-data">
    文件:<input type="file" name="file"/><!-- POST2(上传文件表单) --><br/>
    文件说明:<input type="text" name="desc"/><!-- POST1(普通表单) --><br/><br/>
    文件2:<input type="file" name="file"/><br/>
    文件说明2:<input type="text" name="desc"/>
    <input type="submit" value="上传"/>
  </form>
  <font color="red" size="6">使用apache文件上传工具实现文件上传3(文件打散)</font>
  <!-- POST1(普通表单):enctype=application/x-www-form-urlencoded(默认值) -->
  <!-- POST2(上传文件表单):enctype=multipart/form-data:多部分(不但有文件,也有部分) -->
  <form action="<%=request.getContextPath()%>/upload3" method="post" enctype="multipart/form-data">
    文件:<input type="file" name="file"/><!-- POST2(上传文件表单) --><br/>
    文件说明:<input type="text" name="desc"/><!-- POST1(普通表单) --><br/><br/>
    文件2:<input type="file" name="file"/><br/>
    文件说明2:<input type="text" name="desc"/>
    <input type="submit" value="上传"/>
  </form>
 </body>
</html>

过渡板–了解底层

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("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
    out.println("<HTML>");
    out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
    out.println(" <BODY>");
    out.print("不支持Get方式上传。。。。。。");
    out.println(" </BODY>");
    out.println("</HTML>");
    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<FileItem> 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("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
    out.println("<HTML>");
    out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
    out.println(" <BODY>");
    out.print("不支持Get方式上传。。。。。。");
    out.println(" </BODY>");
    out.println("</HTML>");
    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<FileItem> 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("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
    out.println("<HTML>");
    out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
    out.println(" <BODY>");
    //获取GET方式的url中“?”号后面的部分
    //http://localhost:8080/servletDemo3/upload?name=Jack&sex=male
    String qStr = request.getQueryString();
    System.out.println("qStr: "+qStr);//qStr: name=Jack&sex=male
    out.print("不支持Get方式上传。。。。。。");
    out.println(" </BODY>");
    out.println("</HTML>");
    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<FileItem> 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:

演示上传进度原理

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

(0)

相关推荐

  • JavaBean实现多文件上传的两种方法

    摘要:本文介绍了JavaBean实现多个文件上传的两种方法,分别是使用http协议和ftp协议实现.首先讲述了http协议传送多个文件的基本格式和实现上传的详细过程,之后简单介绍了使用ftpclient 类实现了ftp方式的上传,最后对这两种方法进行了比较. 关键字:JavaBean .http .ftp .ftpclient JavaBean是一种基于Java的软件组件.JSP对于在Web 应用中集成JavaBean组件提供了完善的支持.这种支持不仅能缩短开发时间(可以直接利用经测试和可信任的

  • Java中使用内存映射实现大文件上传实例

    在处理大文件时,如果利用普通的FileInputStream 或者FileOutputStream 抑或RandomAccessFile 来进行频繁的读写操作,都将导致进程因频繁读写外存而降低速度.如下为一个对比实验. 复制代码 代码如下: package test; import java.io.BufferedInputStream;  import java.io.FileInputStream;  import java.io.FileNotFoundException;  import

  • JavaEE实现前后台交互的文件上传与下载

    首先为大家介绍相关的技术: service方法中的两个重要参数. ServletRequest – 用接收用户的请求,它的作用是: 可获取请求头信息. 可设置请请求的字符编码. 可获得用户传递的参数.Post或get. 可获取远程(即访问者)的IP地址. 可获取输入流,如用户上传文件.相片等. 它的一个子接口:javax.servlet.http.HttpServletRequest ServletResponse – 用于向用户返回数据. 设置响应类型- contentType 设置编码-se

  • java实现文件上传下载和图片压缩代码示例

    分享一个在项目中用的到文件上传下载和对图片的压缩,直接从项目中扒出来的:) 复制代码 代码如下: package com.eabax.plugin.yundada.utils; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.

  • JavaWeb实现文件上传与下载实例详解

    在Web应用程序开发中,文件上传与下载功能是非常常用的功能,下面通过本文给大家介绍JavaWeb实现文件上传与下载实例详解. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件.这个common-fileupload上传组件的jar包可以去apache官网上面下载,common-fileupload是依赖于c

  • JavaWeb实现文件上传下载功能实例解析

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件.这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,stru

  • JavaWeb实现文件上传与下载的方法

    文件上传概述 实现web开发中的文件上传功能,需完成如下二步操作: 在web页面中添加上传输入项 在servlet中读取上传文件的数据,并保存到本地硬盘中. 如何在web页面中添加上传输入项? <input type="file">标签用于在web页面中添加文件上传输入项,设置文件上传输入项时须注意: 1.必须要设置input输入项的name属性,否则浏览器将不会发送上传文件的数据. 2.必须把form的enctype属值设为multipart/form-data.设置该值

  • java中struts2实现文件上传下载功能实例解析

    本文实例讲述了java中struts2实现文件上传下载功能实现方法.分享给大家供大家参考.具体分析如下: 1.文件上传 首先是jsp页面的代码 在jsp页面中定义一个上传标签 复制代码 代码如下: <tr>      <td align="right" bgcolor="#F5F8F9"><b>附件:</b></td>      <td bgcolor="#FFFFFF">

  • java结合HADOOP集群文件上传下载

    对HDFS上的文件进行上传和下载是对集群的基本操作,在<HADOOP权威指南>一书中,对文件的上传和下载都有代码的实例,但是对如何配置HADOOP客户端却是没有讲得很清楚,经过长时间的搜索和调试,总结了一下,如何配置使用集群的方法,以及自己测试可用的对集群上的文件进行操作的程序.首先,需要配置对应的环境变量: 复制代码 代码如下: hadoop_HOME="/home/work/tools/java/hadoop-client/hadoop" for f in $hadoo

  • java使用smartupload组件实现文件上传的方法

    本文实例讲述了java使用smartupload组件实现文件上传的方法.分享给大家供大家参考.具体分析如下: 文件上传几乎是所有网站都具有的功能,用户可以将文件上传到服务器的指定文件夹中,也可以保存在数据库中,这里主要说明smartupload组件上传. 在讲解smartupload上传前,我们先来看看不使用组件是怎么完成上传的原理的? 废话不多说直接上代码: 复制代码 代码如下: import java.io.*; import java.util.*; import javax.servle

随机推荐