Java 文件上傳(原理)

openkk 12年前發布 | 5K 次閱讀 PHP庫

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;
    }
}

}</pre>

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!