3

ファイルをアップロードしてサーバーに保存しようとしています。しかし、私は得る:

java.lang.IllegalStateException: File has already been moved - cannot be transferred again

Commons FileUpload jar(CommonsMultipartFile) を使用しています。ステートメントに対して IllegalStateException が発生します。 user.getFileData().transferTo(new File("/home/xavier/uploads/" + user.getFileData().getOriginalFilename()));

こちらuserが豆です。最初はうまくいきましたが、アップロードフォルダーからファイルを削除して再度テストすると、上記のように例外がスローされました。

スタックトレース:

java.lang.IllegalStateException: File has already been moved - cannot be transferred again
    at org.springframework.web.multipart.commons.CommonsMultipartFile.transferTo(CommonsMultipartFile.java:126)
    at com.raistudies.controllers.RegistrationController.processForm(RegistrationController.java:113)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
    at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
    at java.lang.Thread.run(Thread.java:722)
4

2 に答える 2

4

質問で参照する例外には、「ファイルが移動されました - 再度読み取ることはできません」と記載されています。これは、マルチパート ファイルから入力ストリームを複数回読み取ろうとしているためです。

私もかつてこの問題に直面したことがあり、私の場合、まずファイルの内容を検証し、その後、Spring MultiPart の「transferTo」メソッドを使用して保存しようとしました。この例外は、「transferTo」メソッドを使用しようとすると発生します。ここでは、inputstream を 2 回呼び出しています。

ファイル サイズが小さすぎる場合、この問題に直面することはありません。「transferTo」メソッドには、「isAvailable」メソッドの内部呼び出しがあります。以下のコード セグメントに従ってください。

protected boolean More ...isAvailable() {
        // If in memory, it's available.
    if (this.fileItem.isInMemory()) {
        return true;
    }
    // Check actual existence of temporary file.
    if (this.fileItem instanceof DiskFileItem) {
        return ((DiskFileItem) this.fileItem).getStoreLocation().exists();
    }
    // Check whether current file size is different than original one.
    return (this.fileItem.getSize() == this.size);
}

リンク: http://grepcode.com/file/repo1.maven.org/maven2/org.springframework/spring-web/3.2.1.RELEASE/org/springframework/web/multipart/commons/CommonsMultipartFile.java#CommonsMultipartFile.利用可能%28%29

所見:

小さすぎる場合は、スプリングがメモリに保存し、ファイルを要求するとメモリから取得します。ファイルはメモリ内にあるため、複数回要求できます。

それが十分に大きい場合、Spring はそれを場所がわからない一時ファイルとして保存しますが、入力ストリームを読み取った後、そのファイルは Spring によって内部的に削除される可能性があります。次に、2 回目のエラーを要求すると、「再度読み取ることができません」というエラーが表示されます。

したがって、私の解決策は、最初に「transferTo」メソッドを使用してサーバーの場所に保存し、そのローカルファイルを取得して検証するか、その他の2回目の必要があることです。

「multipartResolver」bean の「maxUploadSize」を大きくするのは、ファイルが大きすぎるとメモリを消費するので良くないと思います。

于 2014-06-21T01:43:16.520 に答える