[轉]文件上傳原理:Web上傳文件的原理及實現

  如今有不少Web程序都有上傳功能,實現上傳功能的組件或框架也不少,如基於java的CommonsFileUpload、還有Struts1.x和Struts2中帶的上傳文件功能(實際上,Struts2在底層也使用了CommonsFileUpload)。在asp.net中也有相應的上傳文件的控件。
  雖然如今有不少上傳組件能夠利用,可是瞭解Web上傳文件的原理,對於處理忽然出現的問題會有很大的幫助,下面就來說一下經過瀏覽器上傳文件的基本原理。在瞭解了原理以後,就能夠很是容易地自制知足自身須要的上傳組件了。
  衆所周知,在客戶端代碼中須要使用<input type='file' name='file' />來選擇要上傳的文件,並上傳,代碼如上:html

<html>
<head>
<title>upload</title>
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=GB18030">
</head>
<body>
<form action="servlet/UploadFile"   method="post"   enctype="multipart/form-data">
<input type="file" name="file1" id="file1" />
<input type="file" name="file2" id="file2" />
<input type="submit" value="上傳" />
</form>
</body>
</html>

      從上面的代碼能夠看出,有兩個文件選擇框(file1和file2),在上傳文件時,<form>標籤必須加上enctype="multipart/form-data",不然瀏覽器沒法將文件內容上傳到服務端。下面咱們來作個實驗。在Servlet的doPost方法中編寫以下的代碼,若是想使用asp.net或其餘的語言或技術,也能夠很容易實現相應的功能。java

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
  java.io.InputStream is = request.getInputStream();
  java.io.FileOutputStream fos = new java.io.FileOutputStream("d:\\out.txt");
  byte[] buffer = new byte[8192];
  int count = 0;
  while((count = is.read(buffer)) >0)
  {
    fos.write(buffer, 0, count);
  }
   fos.close();
}

     上面的功能很是簡單,只是經過request得到一個InputStream對象,並經過這個對象從客戶端得到發送過來的字節流(注意,必定要用字節流,由於,上傳的文件多是二進制文件,如圖象文件,所以,使用字節流會更通用)。並將這些字節流保存在D盤的out.txt文件中。而後咱們打開out.txt,文件的內容如圖1所示:瀏覽器

 

      因爲out.txt是使用文本形式打開的,而且file1上傳的是a.jpg(一個圖象文件),所以,顯示的是一些亂碼。咱們能夠不用管它們。只須要看看這些內容的頭部。咱們很快就能夠找到規律。每個文件內容的頭部都由「-----------------------------30514443229777」分隔,而後是這個文件的屬性,以下:
Content-Disposition: form-data; name="file1"; filename="a.jpg"
Content-Type: image/jpeg
  其中包含了文件選擇框的name屬性,還有上傳的文件名(filename字段),要注意的,firefox在上傳時,這個filename屬性值只是文件名,若是使用IE,就是帶路徑的文件名,如D:"a.jpg。
  接下來的規則就和HTTP的頭同樣了,以一個空行("r"n)分隔。後面就是文件的具體內容。如今最關鍵的文件的結尾,從圖1能夠看出,文件的結尾也是框架

「-----------------------------30514443229777」,所以,能夠判定,第一個上傳的文件(包括文件頭)是夾在兩個asp.net

「-----------------------------30514443229777」之間的。而「-----------------------------30514443229777」就是multipart/form-data協議的分隔符但這裏還有一個最關鍵的問題:這個分隔符每次上傳都不同,服務端是如何知道每次上傳的這個分隔符的呢?post

     實際上,這個分隔符是經過HTTP請求頭的Content-Type字段得到,可經過下面的代碼輸出這個字段值:     
      
                System.out.println(request.getHeader("Content-type"));測試

     輸出的內容以下:
                multipart/form-data; boundary=---------------------------106712230227687
     只要在服務端得到boundary後面的值便可。通過測試,Content-Type中的分隔符號中的「-」比實際上傳的「-」少兩個,不知是怎麼回事。不過這不要緊,咱們能夠認爲每個文件塊是以""r"n—「結尾的,或是直接將從boundary得到的分隔符加兩個「—」。而最後結尾的分隔符是
「---------------------------106712230227687—」,後面多了兩個「—」。ui

  綜合上述,也就是說,一個文件塊是以「---------------------------106712230227687」開頭,以「—」結尾,從圖2能夠看出這一切。this

 

                圖2
         至於剩下的工做,就是按着上面的規則來分析這些字符流了。分析的方法不少。在這裏就不詳述了。spa

相關文章
相關標籤/搜索