多文件上传。。。。

多文件上传,搞的头大了,受不了。

 

 

在实现文件上传的时候,form表单中添加或修改为:enctype="multipart/form-data",因为在默认情况下,enctype值为enctype=application/x-www-form-urlencoded,这种编码格式不能够上传文件,而采用multipart/form-data时,表单数据被已二进制的方式被传递出去, 无法正常用request接收,所以搞的令人很头疼。。。。

 

 

下面是我的用servlet实现多文件上传的代码,参考网站:http://blog.sina.com.cn/s/blog_81c2545a0100ybqz.html,他说是可以实现多文件上传,但我测试的结果却是只能上传一个,第二个或第三个择没有上传成功,最后我把一些东西给注释掉,下面会提示。然后就可以了。。。

 

 

浏览器传递出去的消息内容格式(请参考上面的参考网站):

POST / HTTP/1.1
Host: localhost:8091
Connection: keep-alive
Content-Length: 7741
Cache-Control: max-age=0
Origin: null
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.56 Safari/536.5
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryIl2Vzdy7PwfJVaWK
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8
Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3


------WebKitFormBoundaryIl2Vzdy7PwfJVaWK
Content-Disposition: form-data; name="FileID1"


你好
------WebKitFormBoundaryIl2Vzdy7PwfJVaWK
Content-Disposition: form-data; name="FileID2"


发生大幅
------WebKitFormBoundaryIl2Vzdy7PwfJVaWK
Content-Disposition: form-data; name="fileData1"; filename="a.txt"
Content-Type: text/plain

content of a.txt

------WebKitFormBoundaryIl2Vzdy7PwfJVaWK
Content-Disposition: form-data; name="fileData2"; filename="b.txt"
Content-Type: text/plain


content of b.txt

------WebKitFormBoundaryIl2Vzdy7PwfJVaWK
Content-Disposition: form-data; name="uploadfile"


upload
------WebKitFormBoundaryIl2Vzdy7PwfJVaWK--


UploadFileServlet.java

package com.xuezhi.control;


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */


import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


import java.util.HashMap;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.File;
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.FileNotFoundException;
import javax.servlet.RequestDispatcher;


/**
 *
 * @author WJC
 */


public class UploadFileServlet extends HttpServlet {


    /**
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException ,FileNotFoundException{
        doGet(request,response);
    }


    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException ,FileNotFoundException {
        //processRequest(request, response);

        PrintWriter out = response.getWriter();
        
        final int NONE = 0;//状态码,表示没有特殊操作
        final int DATAHEADER = 1;//表示下一行要读到报头信息
        final int FILEDATA = 2;//表示下面要读到表单域的文本值
        final int FIELDDATA = 3;//表示下面要独到表单域的是上传文件和二进制数据




        //请求信息实体的总长度(请求信息中除表头之外的数据长度)
        int totalbytes =request.getContentLength();
        
        //容纳请求信息实体的字节数组
        byte[] b = new byte[totalbytes];
        byte[] srcb = new byte[totalbytes];
        //请求信息类型
        String contentType = request.getContentType();
       


        String fieldname = "";//表单域的名称
        String fieldvalue = "";//表单域的值
        String filename = "";//上传文件名称
        String boundary = "";//分界符字符串
        String lastboundary = "";//结束分界符字符串
        
        String fileFormName = "";
        String fileRealName = "";


        int fileSize = 0;//文件长度


        //容纳表单域的名称/值的哈希表
        HashMap formfields = new HashMap();
        //在消息头类型中找到分界符的定义
        int pos = contentType.indexOf("boundary=");


        String fileID;//上传的文件ID
        if(pos != -1)
        {
            pos += "boundary=".length();
            boundary = "--"+ contentType.substring(pos);
            lastboundary = boundary + "--";//得到结束分界符
        }


        int state = NONE;//起始状态为NONE


        //得到请求信息的数据输入流
        DataInputStream in = new DataInputStream(request.getInputStream());
        in.readFully(srcb);//根据长度,将消息实体的内容读入字节数组b中
        in.close();//关闭数据流
        String reqcontent = new String(srcb);//这里如果你的页面编码用的是utf8的话, 可以修改为String  reqcontent = new String(srcb,"utf-8");
            //从字节数组中的到实体的字符串


        //从字符串中得到输出缓冲流
        BufferedReader reqbuf = new BufferedReader(new StringReader(reqcontent));


        //设置循环标志
        boolean flag = true;
        int i = 0;
        int rootNum = 0;
        while(flag == true)
        {
            String s = reqbuf.readLine();
            if( s == null || s.equals(lastboundary)) break;


            switch(state)
            {
                case NONE :
                    if(s.startsWith(boundary))
                    {
                        //如果独到分界符,择表示下一行一个头信息
                        state = DATAHEADER;
                        i += 1;
                    }
                    break;
                case DATAHEADER :
                    pos = s.indexOf("filename=");
                    //先判断出这是一个文本表单域的头信息,还是一个上传文件的头信息


                    if(pos == -1)
                    {
                        //如果是文本表单域的头信息,解析出表单域的名称


                        pos = s.indexOf("name=");
                        pos += "name=".length() + 1;//1表示后面的”的占位
                        s = s.substring(pos);


                        int L = s.length();
                        s = s.substring(0,L - 1);


                        fieldname = s;//表单域的名称放入fieldname
                        state = FIELDDATA;//设置状态码,准备读取表单域的值
                    }
                    else{
                        //如果是文件数据的头,先存储这一行,用于在字节数组中定位
                        
                        String temp = s;
                        // 先解析出文件名


                        pos = s.indexOf("name=");
                        pos += "name=".length() + 1; // 1表示后面的"的占位
                        int pos2 = s.indexOf("filename=");
                        String s1 = s.substring(pos, pos2 - 3); // 3表示";加上一个空格
                        fileFormName = s1;
                        pos2 += "filename=".length() + 1; // 1表示后面的"的占位
                        s = s.substring(pos2);
                        int l = s.length();
                        s = s.substring(0, l - 1);
                        pos2 = s.lastIndexOf("\\"); // 对于IE浏览器的设置
                        s = s.substring(pos2 + 1);
                        fileRealName = s;
                        
                        out.println("fileRealName = " + fileRealName + "<br>");
                        
                        //下面这一部分从字节数组中取出文件的数据
                       if(fileRealName.length() > 0)
                        {
                        
                        b = srcb;
                        pos = byteIndexOf(b,temp,0);


                        //定位下一行,2表示一个回车和一个换行占2个字节
                        b = subBytes(b,pos + temp.getBytes().length + 2,b.length);


                        //再读一行信息,是这一部分数据的Content-Type
                        s = reqbuf.readLine();


                        //设置文件输入流,准备写文件
//其中request.getSession(true).getServletContext().getRealPath("/")+"../../web/得到项目根目录下的web包,uploadFile是我自己创建的文件夹
                       String path = request.getSession(true).getServletContext().getRealPath("/")+"../../web/uploadFile/"+ fileRealName;

                        File f = new File(path);
                     
                        DataOutputStream fileout = new
                                    DataOutputStream(new FileOutputStream(f));


                        //字节数组再往下一行,4表示两个回车换行符占4个字节,本行的回车换行
                        //2个字节,Content-type的下一行是回车换行表示的空行,占2个字符


                        //得到文件数据的其实位置
                        b = subBytes(b,s.getBytes().length + 4 ,b.length);
                        pos = byteIndexOf(b,boundary,0);//定位文件数据的结尾
                        b = subBytes(b,0,pos -1);//获取文件数据
                        fileout.write(b,0,b.length - 1);//将文件数据存盘
                        fileout.close();
                        fileSize = b.length - 1;//文件长度存入fileSize
                        
                        formfields.put(fileFormName,fileRealName);
                        rootNum ++;//文件路径编号root1....n
                        
                        formfields.put("root"+rootNum,path);
                        state = NONE;//修改前为state=FILEDATA
                        }
                    }
                    break;
                case FIELDDATA :
                    //读出表单域的值
                    s = reqbuf.readLine();
                    fieldvalue = s;//存入fieldvalue
                    formfields.put(fieldname,fieldvalue);
                    state = NONE;


                    break;
               /* 

*在注释掉这这部分和未修改上面红字部分之前,同时上传多个文件,只能接收到第一个文件,后面的都接收不到

case FILEDATA :
                    //如果是文件数据不进行分析,直接读过去


                    while((!s.startsWith(boundary)) && (!s.startsWith(lastboundary)))
                    {
                        s = reqbuf.readLine();
                        if(s.startsWith(boundary))
                        {
                            state = DATAHEADER;
                        }
                        else break;
                        break;
                    }
                    break;
                */

            }
        }


        //指定内容类型,并且可显示为中文
        
        
        out.println("<HTML>");
        out.println("<HEAD><TITLE>上传文件结果</TITLE></HEAD>");
        out.println("<BODY>");//HTML的头
        out.println("<H1>文件上传结果</H1><hr>");
        out.println(
                "ID 为" + formfields.get("FileID1") + "的文件\n"
                    +"和ID 为" + formfields.get("FileID2") + "的文件\n"
                +formfields.get("FileData1") + "已经上传\n" 
                +formfields.get("FileData2") + "已经上传"
                );
        out.println("<br>");
        out.println("contentType="+contentType);
        out.println("<br>");
        out.println("totalBytes="+totalbytes);
        out.println("</BODY>");
        out.println("</HTML>");//HTML的结尾
        

        
    }


    /**
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>


   /**
     * 字节数组中的indexof函数,与String类中的indexOf类似,
     * b要搜索的字节数组
     * s要找的字符串
     * start搜索的起始位置
     * 如果找到,返回s的第一个字节在buffer中的下标,没有就返回-1
     */


    private static int byteIndexOf(byte[] b,String s,int start)
    {
        return byteIndexOf(b,s.getBytes(),start);
    }


    /**
     * 字节数组中的indexof函数,与String类中的indexOf类似
     * b源字节数组
     * s目标自己数组
     * start搜做的起始位置
     * 如果找到,返回s的第一个字节在b中的下标,没有就返回-1
     */


     private static int byteIndexOf(byte[] b,byte[] s,int start)
     {
         int i ;
         if(s.length == 0)
         {
              return 0;
         }
         int max = b.length - s.length;
         if(max < 0)
             return - 1;
         if( start > max )
             return -1;
         if(start < 0)
             start = 0;


         //在b中找到s的第一个元素
         search :
            for(i = start;i <= max;i++)
            {
                if(b[i] == s[0])
                {
                    //找到了s中的第一个元素后,比较剩余的部分是否相等
                    int k = 1;
                    while(k < s.length)
                    {
                        if(b[k + i] != s[k])
                        {
                            continue search;
                        }
                        k++;
                    }
                    return i;
                }
            }
            return -1;


     }


     /**
      * 用于从一个字节数组中提取一个字节数组
      * 类似于String类的苏北String()
      */
     private static byte[] subBytes(byte[] b,int from,int end)
     {
         byte[] result = new byte[end - from];
         System.arraycopy(b, from, result, 0, end - from);


         return result;
     }


     /**
      * 用于从一个字节数组中提取一个字符串
      * 类似于String中的substring()
      */


     private static String subBytesString(byte[] b,int from ,int end)
     {
         return new String(subBytes(b,from,end));
     }
}

//end of UploadFileServelt.java


jsp页面如下:upload.jsp

<%@page contentType="text/html" pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    </head>
    <body>
        <form method="post" action="UploadFileServlet" enctype="multipart/form-data">
            <p>flag:<input type="text" name="flag" size= "20"></p>
            <p>ID:<input type="text" name="FileID1" size="20"></p>
            <p>ID:<input type="text" name="FileID2" size="20"></p>
            <p>文件名1:<input type="file" name="FileData1" size="20"></p>
            <p>文件名2:<input type="file" name="FileData2" size="20"></p>
            
            <input type="submit" name="upload" value="upload">            
        </form>
    </body>
</html>

当然,你可以采用组件来做,那样简单方便。唉,我这是被逼得,组长不让用组件,结果我快被搞死了

采用组件的多文件上传参考网站:http://blog.youkuaiyun.com/tgm316750432/article/details/7952307

struts中文件上传也是相当的给力,可以找一下。。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值