我對表單上傳的理解(可能有誤):
?<form action="" method="post" enctype="multipart/form-data">
?最大上傳2G.
通過 http 協議上傳文件(rfc1867協議概述,jsp 應用舉例,客戶端發送內容構造)?服務器接收到上傳的流,自己其實是不作任何處理的,那個request還是原裝的,誰來處理這個request呢,一般采用第三方的工具,這里以commons fileupload為例.
?
DiskFileItemFactory?factory?=?new?DiskFileItemFactory();
factory.setSizeThreshold(4096);//?設置緩沖,這個值決定了是fileinputstream還是bytearrayinputstream
factory.setRepository(new File("d:\\temp"));//設置臨時存放目錄,默認是new File(System.getProperty("java.io.tmpdir"))
ServletFileUpload?sfu?=?new?ServletFileUpload(factory);
sfu.setSizeMax(100*1024*1024);//100M
List items?=?sfu.parseRequest(request);//傳入的這個request還是原裝的
?見上面的代碼,commons fielupload通過ServletFileUpload類的
parseRequest(request)方法處理這個原始流。而ServletFileUpload
又會調用其爺爺類FileUploadBase的parseRequest(request)方法,然后又會調return parseRequest(new ServletRequestContext(request)),代碼如下
????????try?{
????????????FileItemIterator?iter?=?getItemIterator(ctx);
????????????List?items?=?new?ArrayList();
????????????FileItemFactory?fac?=?getFileItemFactory();
????????????if?(fac?==?null)?{
????????????????throw?new?NullPointerException(
????????????????????"No?FileItemFactory?has?been?set.");
????????????}
????????????while?(iter.hasNext())?{
????????????????FileItemStream?item?=?iter.next();
????????????????FileItem?fileItem?=?fac.createItem(item.getFieldName(),
????????????????????????item.getContentType(),?item.isFormField(),
????????????????????????item.getName());
????????????????try?{
????????????????????Streams.copy(item.openStream(),?fileItem.getOutputStream(),
????????????????????????????true);
????????????????}?catch?(FileUploadIOException?e)?{
????????????????????throw?(FileUploadException)?e.getCause();
????????????????}?catch?(IOException?e)?{
????????????????????throw?new?IOFileUploadException(//報錯經常在這里
????????????????????????????"Processing?of?"?+?MULTIPART_FORM_DATA
????????????????????????????+?"?request?failed.?"?+?e.getMessage(),?e);
????????????????}
????????????????if?(fileItem?instanceof?FileItemHeadersSupport)?{
????????????????????final?FileItemHeaders?fih?=?item.getHeaders();
????????????????????((FileItemHeadersSupport)?fileItem).setHeaders(fih);
????????????????}
????????????????items.add(fileItem);
????????????}
????????????return?items;
????????}?catch?(FileUploadIOException?e)?{
????????????throw?(FileUploadException)?e.getCause();
????????}?catch?(IOException?e)?{
????????????throw?new?FileUploadException(e.getMessage(),?e);
????????}
????
?這里注意,上傳的<input type=file>標記一定要有name,如果沒有,commons fielupload不作處理。
?commons fielupload會把上傳的文件以流的方式寫入到temp文件夾,臨時文件夾可以自己設定,如果不手動設置,則是Servlet容器為web應用分配的臨時目錄,tomcat可能就是
%TOMCAT_HOME%\temp,我用weblogic時,是
C:\DOCUME~1\yourname\LOCALS~1\Temp\。這些臨時文件以"upload"開頭,格式是.tmp,例如
"upload_47fdc3_11c9eb678b0__8000_00000043.tmp"?在上傳過程中commons fielupload才知道上傳的文件的大小,如果你定義允許的最大附件為100M,然后你上傳一個200M的文件,那么只有實際傳輸了100M以后,commons fielupload才知道超過了,然后拋出一個異常(
org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException)。
?commons fielupload處理完了以后(處理過程全在
parseRequest(request)方法里),返回一個List,里面的每一項已被封裝為FileItem,你通過
fileItem.isFormField()判斷出是普通的表單屬性呢,還是一個文件,如果是文件,你可以從
fileItem.getInputStream()獲得輸入流,這個輸入流其實是一個FileInputStream.當然,如果文件很小,則是ByteArrayInputStream.那么如何區分?這兩者的區別是由
factory.setSizeThreshold(4096)確定的。大于4K,為FileInputStream,小于4K為ByteArrayInputStream
這樣就可以解釋struts用ActionForm的方式處理上傳附件的一些問題了,struts接收到enctype="multipart/form-data"的post請求后,會看那個對應的action有沒有配置actionform,如果配置了,就會作一些處理,所以你在action里得到的request已經不是一個普通的request了,而是一個被封裝過的request。如果想得到原始的request,就不要struts-config.xml里給action類配置actionform
tempDir指定的目錄中可能會隨著時間推移出現很多后綴為"tmp"的垃圾文件,commons-fileupload1.2提供了一個不錯的解決方法,就是把下面的代碼加入到web.xml中即可。
<listener>
<listener-class>
org.apache.commons.fileupload.servlet.FileCleanerCleanup
</listener-class>
</listener>
來源:
http://fratemity1314.spaces.live.com/Blog/cns!E3BCC13A1E72BB4F!222.entryQ:I'm using FileUpload in an Action, but it's not working. Why?
A:Struts
recognises multipart requests, and parses them automatically,
presenting the request parameters to your code in the same manner as if
they were regular request parameters. Since struts has already processed the request, and made it available in your form
bean, the input stream is no longer available for parsing, so
attempting to do so with FileUpload will fail.
Q:But I need to parse the request myself. How can I do that?
A:Struts
parses multipart a request as a part of the process of populating your
form bean from that request. If, for some reason, you need to have full
control over the multipart parsing, you can do so by configuring your
action mapping without an associated form bean. (A better way of doing
this, however, is to replace the default multipart handler with your
own. See the struts documentation for details.) 1,直接用commons fileupload而不用struts的ActionForm時,表單里的屬性值不能用request.getParameter()獲取了,而url里的queryString可以。
2,? 獲取form里的屬性值的代碼

????????????????????String?formname?=?fi.getFieldName();//?獲取form中的名字
????????????????????String?formcontent?=?fi.getString();

????????????????????if?(formname.equals("id"))?
{
????????????????????????id?=?formcontent;

????????????????????}?else?if?(formname.equals("title"))?
{
????????????????????????title?=?formcontent;

????????????????????}?else?if?(formname.equals("memo"))?
{
????????????????????????memo?=?formcontent;
????????????????????}
????????????????3, 表單里的file控件的name不能為空。
4,上傳大文件(190多M)時報異常
org.apache.commons.fileupload.FileUploadException: ? Processing ? of ?
multipart/form-data ? request ? failed. ? EOF ? after ? reading ? only:
? "3567789 " ? of: ? "203323339 " ? promised ? bytes, ? out? of ? which ? at ? least: ? "0 " ? were ? already ? buffered
http://forums.bea.com/thread.jspa?threadID=200033356
http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=121&threadID=20060&start=0&tstart=0
http://thisisxy.blogcn.com/diary,204014352.shtml
http://www.80diy.com/home/20050527/17/4040711.html
5,
org.apache.commons.fileupload.FileUploadException: Processing of multipart/form-data request failed. Read timed out
HTTP活動超時限制的時間太短 HTTP Keep-Alive Timeout.
6,InputStream is =formFile.getInputStream() ;? //formFile是org.apache.struts.upload.FormFile
上傳的文件小時這個輸入流是java.io.ByteArrayInputStream,上傳比較大的文件時這個輸入流是FileInputStream
7,設置表單里的上傳路徑為只讀
<input type=file id="uploadfile" name="uploadfile" style="display: none;">
<input type=text id=tempfile readonly="true">
<input type=button
onClick="uploadfile.click();tempfile.value=uploadfile.value;" value="瀏覽..">
10,
http://eastpoint.javaeye.com/blog/99084
http://topic.csdn.net/u/20080131/13/649c57c7-204e-4bb6-9b09-49cca39f00b8.html
http://blog.niwota.com/nb/chenchuang?cat_self_id=291075