MDA/MDD/TDD/DDD/DDDDDDD
posts - 536, comments - 111, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

使用commons fileupload的零碎笔记

Posted on 2007-08-27 11:58 leekiang 阅读(29161) 评论(6)  编辑  收藏 所属分类: fileupload
我对表单上传的理解(可能有误):
 <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.entry

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

评论

# re: 使用commons fileupload的零碎笔记  回复  更多评论   

2008-10-31 15:27 by leekiang
对于post和get的参数,好像commons fileupload的处理是不一样的,get参数可以直接通过request.getParameter()的方式获取,而post的不行,待验证。

# re: 使用commons fileupload的零碎笔记  回复  更多评论   

2009-07-23 10:24 by 尹伟杰
我现在就遇到了这样的问题

# re: 使用commons fileupload的零碎笔记  回复  更多评论   

2009-07-23 10:27 by 尹伟杰
一次性上传卫星照片4个 大于2G weblogic报错 超时 但是 改成4个form分开
一个form 965m 也报错 都晕了,你当时是怎么解决的???
我的qq是838303967

# re: 使用commons fileupload的零碎笔记  回复  更多评论   

2009-07-23 10:29 by 尹伟杰
Processing of multipart/form-data request failed. EOF after reading only: '38535168' of: '967898783' promised bytes, out of which at least: '0' were already buffered 报的错!!!

# re: 使用commons fileupload的零碎笔记  回复  更多评论   

2009-07-28 18:49 by 尹伟杰
哥们你赶快上线啊!!我的快疯了!!!我的电话是13146277259 qq是838303967!!!

# re: 使用commons fileupload的零碎笔记  回复  更多评论   

2010-08-30 21:58 by gogoes
throw new IOFileUploadException(//报错经常在这里
"Processing of " + MULTIPART_FORM_DATA
+ " request failed. " + e.getMessage(), e);


我现在处理大量用户数据时,老是这里出错,出错信息如下:
Caused by: org.apache.commons.fileupload.FileUploadException: Processing of multipart/form-data request failed. Stream ended unexpectedly
at com.alibaba.service.upload.patch.ServletFileUpload.parseRequest(ServletFileUpload.java:162)
at com.alibaba.service.upload.patch.ServletFileUpload.parseRequest(ServletFileUpload.java:40)
at com.alibaba.service.upload.DefaultUploadService.parseRequest(DefaultUploadService.java:165)

能帮看看,有什么解决的办法吗?

只有注册用户登录后才能发表评论。


网站导航: