Java 文件上传(原理)

package com.svse.upload;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class UploadServlet extends HttpServlet{
    protected String encoding = "UTF-8";
    protected String decoding = null;
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
    {
        /*****
         * -----------------------------7d91463b90688
            Content-Disposition: form-data; name="p1"
            
            li
             -----------------------------7d91463b90688
            Content-Disposition: form-data; name="p2"
            
            heng
             -----------------------------7d91463b90688
            Content-Disposition: form-data; name="f1"; filename="D:\HelloWorld.java"
            Content-Type: text/plain
            
            import javax.microedition.midlet.*;
            import javax.microedition.lcdui.*;
             
            public class HelloWorld extends MIDlet
             {
                
            }
            -----------------------------7d91463b90688--
         */
        request.setCharacterEncoding("UTF-8");//设定输入的格式
        response.setCharacterEncoding("UTF-8");//设定输入的格式
        ServletInputStream sis = request.getInputStream();//得到输入流
        int len = request.getContentLength();//得到内容的长度
        
        int index = 0;
        String tmp = null;//临时保存一行数据的变量
        boolean isFirst = true;//第一次访问的时候
        String firstLine = null;//保存第一行数据作为结束的标志
        System.out.println("the content lenth is: "+len);
        //iindex 能把读 ServetInputStream 位元组的计数的长度存档
        int[] iindex = new int[1];//记录每一次读取的字节的数
        byte[] bytes = new byte[4096];//缓冲数组的大小
        //文件名
        String filename = null;
        //循环读取请求头中的内容
        while((tmp = readLine(bytes, iindex, sis, encoding)) != null)
        {
            if(isFirst)//判断是否是第一行
            {
                firstLine = tmp;//将第一行数据保存下来
                isFirst = false;//将标识改为false
            }
            //判断是否到达客户上传的文件的文件名的那一行数据
            index = tmp.indexOf("filename=");
            if(index != -1)
            {   
                //  Content-Disposition: form-data; name="f1"; filename="110425030337-0.jpg"
                String tailString = tmp.substring(index+10);//将文件名截取下来 110425030337-0.jpg"
                System.out.println("指针到文件名开始标志-->:index="+index+"tailString="+tailString);
                if(tailString != null)
                {//截取下来的文件的名字的最后还包含一个引号,得到引号的下标
                    int ii = tailString.indexOf("\"");
                    //再次截取字符串得到文件名
                    filename = tailString.substring(0,ii);
                }
                System.out.println("得到文件名的时候:tmp="+tmp);
                break;//下一行就是上传的文件的数据所以就跳出循环
            }
            
        }
        
        filename = getName(filename);
        
        if(filename == null)//如果文件名为空那么将随意给一个名字避免出现bug
        {
            filename = "file.out1";
        }
        //文件写出的地址
        String filepath = "d:/"+filename;
        //初始化输出流对象
        FileOutputStream fos = new FileOutputStream(filepath);
        
        String endFlag = firstLine.substring(0, firstLine.length() -2)+"--"+firstLine.substring(firstLine.length() -2);
        System.out.println("firstLine元数据"+firstLine);
        System.out.println("前一段截取:"+firstLine.substring(0, firstLine.length() -2));
        System.out.println("后一段截取:"+firstLine.substring(firstLine.length() -2));
        System.out.println("结束的标识符:"+endFlag);
        //因为下一行是上传的文件的数据类型  所以就读取一下将指针移动到下一行 下一行就是客户上传的数据的所有的内容
        String contentType = readLine(bytes, iindex, sis, encoding);
        System.out.println("Content-Type is : "+contentType);
        if(contentType != null)
        {
            if(contentType.indexOf("Content-Type") == -1)
            {
                System.out.println(contentType);
            }
            else
            {//经接着是换行\r\n所以将指针向下移动一行
                System.out.println("the head of file: "+readLine(bytes, iindex, sis, encoding));
            }
        }
        
        //从现在开始读取的数据就是客户端上传的文件的数据
        boolean tt = false;
        int mark = 0;
        byte[] backups = new byte[4096];
        while((tmp = readLine(bytes, iindex, sis, encoding)) != null)
        {
            if(endFlag.equals(tmp))
            {
                if(mark >2)
                {
                    //现在指针已经读取到最后的一行数据所以不能在往下读取了
                    System.out.println("文件到了最后:"+mark);
                    //将上一行的数据写入指定的文件为什么要减2因为最后一行的数据有一个\r\n占用2个字节   二进制的数据回车换行是0D 0A
                    fos.write(backups, 0, mark-2);
                    fos.flush();
                }
                break;//文件写出完毕
            }
            else//下一次写出上一次的数据
            {
                if(tt)
                {
                    fos.write(backups, 0, mark);
                    fos.flush();
                }
                mark = iindex[0];
                for(int i=0;i<iindex[0];i++)
                {
                    backups[i] = bytes[i];
                }
                tt = true;
            }
        }
        
        fos.close();
        sis.close();
        
    }
    /***
     * 因为每种浏览器的上传的文件的名字不一样
     * 所以还需要判断是否是文件的全路径如果是那么将文件的名字截取下来
     * 返回
     * @param name
     * @return
     */
    protected String getName(String name)
    {
        String rtn = null;
        System.out.println("传入的全部的名称:"+name);
        if(name != null)
        {
            int index = name.lastIndexOf("/");
            if(index != -1)
            {
                rtn = name.substring(index +1);
            }
            else
            {
                index = name.lastIndexOf("\\");
                if(index != -1)
                {
                    rtn = name.substring(index +1);
                }
                else
                {
                    rtn = name;
                }
            }
        }
        return rtn;
    }
    
    //读取来自客户端请求的数据每次读取一行将其返回
    protected String readLine(byte[] bytes, int[] index, ServletInputStream sis, String enconding)
    {
        try {
            index[0] = sis.readLine(bytes, 0, bytes.length);
            if(index[0] < 0)
                return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        try{
            if(encoding == null)
            {
                return new String(bytes, 0, index[0]);
            }
            else
            {
                return new String(bytes, 0, index[0], encoding);
            }
        }catch(Exception e)
        {
            return null;
        }
    }
}



posted @ 2012-05-03 13:17  j2ee技术  阅读(405)  评论(0编辑  收藏  举报