Apache FileUpload

1.解析servlet request,做出对应的响应。

2.文件的上传下载,就是操作IO的。故需要Conmmons io支持。

3.FileItem对上传的数据来源,进行了封装了,使得,我们可以进行统一的处理。那么每一个上传的数据源,就对应一个FileItem。FileItemFactory负责创建FileItem。工厂创建的FileItem,可以决定上传的数据存储的位置,在内存或者文件中,根据应用需要。

4.FileUpload可以应用在servlet and portlet environments.这两个环境中,但是这两个环境还是存在差异的。

     Where you see references to the ServletFileUpload class, substitute the PortletFileUpload class.
    Where you see references to the HttpServletRequest class, substitute the ActionRequest class. 

5.通过一个类静态方法,验证servlet request,是否是一个文件上传请求。

// Check that we have a file upload request
boolean isMultipart = ServletFileUpload.isMultipartContent(request);

6.最简单的文件上传功能:

    文件上传基本原则 

       @1.上传的资源合理的小,应该放置在内存中,

       @2.比较大的资源应该放置在文件中,

       @3.上传的每个文件有大小限制,上传的总的大小有限制,上传的临时路径需要指定

       @4.过大的上传请求,是不被执行的。

上传代码

// Create a factory for disk-based file items
FileItemFactory factory = new DiskFileItemFactory();

// Configure a repository (to ensure a secure temp location is used)
ServletContext servletContext = this.getServletConfig().getServletContext();
File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
factory.setRepository(repository);

// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);

// Parse the request
List<FileItem> items = upload.parseRequest(request);
7.针对上述的文件上传,想再添加一些额外的要求,我们可以从upload handler or the file item factory or both这三者进行入手。譬如:

// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();

// Set factory constraints
factory.setSizeThreshold(yourMaxMemorySize);
factory.setRepository(yourTempDirectory);

// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);

// Set overall request size constraint
upload.setSizeMax(yourMaxRequestSize);

// Parse the request
List<FileItem> items = upload.parseRequest(request);
上述的配置,仅仅使用一次,使用完了,还得继续搜集,要 一劳永逸的方法就是:

// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory(yourMaxMemorySize, yourTempDirectory);
除了,上述的外,我们还可自定义,文件的上传路径,譬如上传到数据库中。待续...

8.上述的方法中,我们得到了要保存的文件,那么要做的就是,保存这些文件。

// Process the uploaded items
Iterator<FileItem> iter = items.iterator();
while (iter.hasNext()) {
    FileItem item = iter.next();

    if (item.isFormField()) {
        processFormField(item);
    } else {
        processUploadedFile(item);
    }
}
processFormField(item);
这个方法可能是这样的:

// Process a regular form field
if (item.isFormField()) {
    String name = item.getFieldName();
    String value = item.getString();
    ...
}
而这个方法可能是这样的:
 processUploadedFile(item);
// Process a file upload
if (!item.isFormField()) {
    String fieldName = item.getFieldName();
    String fileName = item.getName();
    String contentType = item.getContentType();
    boolean isInMemory = item.isInMemory();
    long sizeInBytes = item.getSize();
    ...
}
也可能是这样的:将文件保存到最终的某个地方或者是变成inputstream 
   
   
   
   
// Process a file upload
if (writeToFile) {
    File uploadedFile = new File(...);
    item.write(uploadedFile);
} else {
    InputStream uploadedStream = item.getInputStream();
    ...
    uploadedStream.close();
}
但是,write(),在调用的过程中,会尝试着去重新命名文件。因为某写原因或者资源在内存中使用,重新命名失败,那么write()所做的就是,复制资源到最终的地方。

如果,希望使用内存中的资源,那么可以使用:

// Process a file upload in memory
byte[] data = item.get();
9.类似 DiskFileItem,在文件上传中,产生的临时文件,是会在 java.io.File对象被回收时, org.apache.commons.io.FileCleaner实例,自动进行回收。自动回收的进行需要在webapp的web.xml中进行配置

<web-app>
  ...
  <listener>
    <listener-class>
      org.apache.commons.fileupload.servlet.FileCleanerCleanup
    </listener-class>
  </listener>
  ...
</web-app>
10.我们如何得到FileCleaner实例呢?我们可以通过如下方式获取:
The FileCleanerCleanup provides an instance of org.apache.commons.io.FileCleaningTracker

public static DiskFileItemFactory newDiskFileItemFactory(ServletContext context,
                                                         File repository) {
    FileCleaningTracker fileCleaningTracker
        = FileCleanerCleanup.getFileCleaningTracker(context);
    DiskFileItemFactory factory
        = new DiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD,
                                  repository);
    factory.setFileCleaningTracker(fileCleaningTracker);
    return factory;
}
//注意:FileCleaningTracker to null时,自动删除临时文件,就不会得到进行了。
11.文件上传,往往会触发系统上的病毒扫描。病毒扫描时,往往会就文件移到沙箱中进行,但是,上传的文件由于持有特殊的引用,而病毒扫描软件无法获取,那么就会使得病毒潜在。这就需要额外的扫描程序进行了。这里也不是文件上传所能介绍的,我理解的也是有限的,请多多批评指教。

12.文件在上传的过程中,我们很希望可以看到上传的进度情况。

进度的获取,我们呢,通过一个匿名的progress listener(进度监听类),

//Create a progress listener
ProgressListener progressListener = new ProgressListener(){
   public void update(long pBytesRead, long pContentLength, int pItems) {
       System.out.println("We are currently reading item " + pItems);
       if (pContentLength == -1) {
           System.out.println("So far, " + pBytesRead + " bytes have been read.");
       } else {
           System.out.println("So far, " + pBytesRead + " of " + pContentLength
                              + " bytes have been read.");
       }
   }
};
upload.setProgressListener(progressListener);
但是,这个进度监听函数,可能成为你应用中的一个性能问题。因为,监听每隔一定时间,会重复调用,那么就会带来性能问题。

常用的方法就是,监听函数,不要进行的太活跃。

//Create a progress listener
ProgressListener progressListener = new ProgressListener(){
   private long megaBytes = -1;
   public void update(long pBytesRead, long pContentLength, int pItems) {
       long mBytes = pBytesRead / 1000000;
       if (megaBytes == mBytes) {
           return;
       }
       megaBytes = mBytes;
       System.out.println("We are currently reading item " + pItems);
       if (pContentLength == -1) {
           System.out.println("So far, " + pBytesRead + " bytes have been read.");
       } else {
           System.out.println("So far, " + pBytesRead + " of " + pContentLength
                              + " bytes have been read.");
       }
   }
};
更加复杂代码的文件上传,需要结合其JavaDoc完成。



你可能感兴趣的:(java,fileupload)