隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0
          數據加載中……

          Web上傳文件的原理及實現

          本文為原創,如需轉載,請注明作者和出處,謝謝!

          現在有很多Web程序都有上傳功能,實現上傳功能的組件或框架也很多,如基于javaCommons FileUpload、還有Struts1.xStruts2中帶的上傳文件功能(實際上,Struts2在底層也使用了Commons FileUpload)。在asp.net中也有相應的上傳文件的控件。

          雖然現在有很多上傳組件可以利用,但是了解Web上傳文件的原理,對于處理突然出現的問題會有很大的幫助,下面就來講一下通過瀏覽器上傳文件的基本原理。在了解了原理之后,就可以非常容易地自制滿足自身需要的上傳組件了。

          眾所周知,在客戶端代碼中需要使用<input type='file' name='file' />來選擇要上傳的文件,并上傳,代碼如上:

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

          從上面的代碼可以看出,有兩個文件選擇框(file1file2),在上傳文件時,<form>標簽必須加上enctype="multipart/form-data",否則瀏覽器無法將文件內容上傳到服務端。下面我們來做個實驗。在ServletdoPost方法中編寫如下的代碼,如果想使用asp.net或其他的語言或技術,也可以很容易實現相應的功能。

              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所示:



                                                                                                    圖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”,因此,可以斷定,第一個上傳的文件(包括文件頭)是夾在兩個“-----------------------------30514443229777”之間的。而“-----------------------------30514443229777”就是multipart/form-data協議的分隔符。但這里還有一個最關鍵的問題。這個分隔符每次上傳都不一樣,服務端是如何知道每次上傳的這個分隔符的呢?

          實際上,這個分隔符是通過HTTP請求頭的Content-Type字段獲得,可通過下面的代碼輸出這個字段值:

          System.out.println(request.getHeader("Content-type"));

          輸出的內容如下:

          multipart/form-data; boundary=---------------------------106712230227687

          只要在服務端獲得boundary后面的值即可。經過測試,Content-Type中的分隔符號中的“-”比實際上傳的“-”少兩個,不知是怎么回事。不過這沒關系,我們可以認為每一個文件塊是以""r"n—“結尾的,或是直接將從boundary獲得的分隔符加兩個“”。而最后結尾的分隔符是“---------------------------106712230227687—”,后面多了兩個“”。

          綜合上述,也就是說,一個文件塊是以“---------------------------106712230227687”開頭,以“”結尾,從圖2可以看出這一切。



                                            圖2

              至于剩下的工作,就是按著上面的規則來分析這些字符流了。分析的方法很多。在這里就不詳述了。

          multipart/form-data規 范原文:http://www.ietf.org/rfc/rfc2388.txt

          Form-based File Upload in HTML:http://www.ietf.org/rfc/rfc1867.txt






          Android開發完全講義(第2版)(本書版權已輸出到臺灣)

          http://product.dangdang.com/product.aspx?product_id=22741502



          Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


          新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

          posted on 2008-05-29 12:42 銀河使者 閱讀(6784) 評論(1)  編輯  收藏 所屬分類: javaweb 原創

          評論

          # re: Web上傳文件的原理及實現  回復  更多評論   

          ASP有沒有辦法直接獲取上傳文件部分的內容?
          2009-11-27 11:00 | 網絡監控
          主站蜘蛛池模板: 吉安县| 旬阳县| 明溪县| 柳江县| 荣成市| 吴桥县| 三亚市| 闵行区| 竹溪县| 始兴县| 宾阳县| 巩义市| 开平市| 梁平县| 五华县| 汨罗市| 高要市| 漠河县| 萍乡市| 武安市| 临漳县| 宁安市| 米脂县| 广元市| 溆浦县| 阳城县| 沐川县| 介休市| 蕉岭县| 沙湾县| 九台市| 万盛区| 麻阳| 丰县| 蓬莱市| 万州区| 揭东县| 定日县| 宜良县| 九龙城区| 涿鹿县|