ひがやすを技術ブログ

電通国際情報サービスのプログラマ

アップロードのときにFormFile#destroy()を呼ぶ必要があるかどうか

うちの嫁に聞かれた(家で技術的な話をするのはほとんどないんだけどね)ので、答えておくと、通常は、GCのタイミングで、テンポラリのファイルが削除されるので、明示的に呼ぶ必要はありません。
ソースで言うと、org.apache.commons.fileupload.disk#finalize()が最終的には呼ばれるので、問題ありません。
ただ、セッションにアクションフォームを入れていて、かつセッションからアクションフォームを削除するのを忘れていると問題が起きる可能性があります。


確実にやりたいなら、専用のMultipartRequestHandlerを用意すること。次のような感じ。
ポイントは、MyFormFile#getFileData()でdestroy()を呼び出していること。一度データをとった後は、開放してかまいません。

public class MyMultipartRequestHandler extends CommonsMultipartRequestHandler {
    @Override
    protected void addFileParameter(FileItem item) {
        FormFile formFile = new MyFormFile(item);

        elementsFile.put(item.getFieldName(), formFile);
        elementsAll.put(item.getFieldName(), formFile);
    }

    protected static class MyFormFile implements FormFile, Serializable {

        private static final long serialVersionUID = 1L;

        private FileItem fileItem;

        private byte[] fileData;

        public S2FormFile(FileItem fileItem) {
            this.fileItem = fileItem;
        }

        public String getContentType() {
            return fileItem.getContentType();
        }

        public void setContentType(String contentType) {
            throw new UnsupportedOperationException(
                    "The setContentType() method is not supported.");
        }

        public int getFileSize() {
            return (int) fileItem.getSize();
        }

        public void setFileSize(int filesize) {
            throw new UnsupportedOperationException(
                    "The setFileSize() method is not supported.");
        }

        public String getFileName() {
            return getBaseFileName(fileItem.getName());
        }

        public void setFileName(String fileName) {
            throw new UnsupportedOperationException(
                    "The setFileName() method is not supported.");
        }

        public byte[] getFileData() throws FileNotFoundException, IOException {
            if (fileData == null) {
                fileData = fileItem.get();
                destroy();            
            }           
            return data;
        }

        public InputStream getInputStream() throws FileNotFoundException,
                IOException {
            return fileItem.getInputStream();
        }

        public void destroy() {
            fileItem.delete();
        }

        protected String getBaseFileName(String filePath) {
            String fileName = new File(filePath).getName();
            int colonIndex = fileName.indexOf(":");
            if (colonIndex == -1) {
                colonIndex = fileName.indexOf("\\\\");
            }
            int backslashIndex = fileName.lastIndexOf("\\");
            if (colonIndex > -1 && backslashIndex > -1) {
                fileName = fileName.substring(backslashIndex + 1);
            }
            return fileName;
        }

        @Override
        public String toString() {
            return getFileName();
        }
    }