我完全按照this教程中的说明构建了Spring Boot应用程序,用于上传单个文件。我所做的更改如下所述。
我已向application.properties
添加了以下属性:
spring.http.multipart.max-file-size=2048MB
spring.http.multipart.max-request-size=2048MB
然后,我在项目运行配置中添加了以下jvm参数,以将jvm堆大小限制为2GB,如this answer中所述:
-Xmx2048m
接下来,我还确保我的Spring Boot应用程序针对64位Java运行,因为it seems that 32位Java需要“连续的”堆空间来保留。
但是,当我尝试上传大文件时,仍然出现相同的错误。
首先,我尝试上传20MB文件。有效。接下来,我一直尝试使用价值1GB的ubuntu iso,但它始终给我以下异常:
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3236) ~[na:1.8.0_74]
at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118) ~[na:1.8.0_74]
at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93) ~[na:1.8.0_74]
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153) ~[na:1.8.0_74]
at org.springframework.util.StreamUtils.copy(StreamUtils.java:128) ~[spring-core-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.util.FileCopyUtils.copy(FileCopyUtils.java:109) ~[spring-core-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.util.FileCopyUtils.copyToByteArray(FileCopyUtils.java:156) ~[spring-core-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.getBytes(StandardMultipartHttpServletRequest.java:291) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at com.digitate.ignio.spring_boot_hdfs_file_upload.controller.UploadController.singleFileUpload(UploadController.java:73) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_74]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_74]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_74]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_74]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:220) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
当前,我在计算机上安装了8GB RAM,并有1.5GB的可用空间。当有2 GB以上的可用RAM时,我还尝试运行spring boot app。
在调试过程中,我可以看到上传文件的大小确实为1 + GB:
但是在执行第73行file.getBytes()
时,它抛出了异常。
我在这里想念什么?
答案 0 :(得分:1)
处理大文件时,将整个文件加载到内存中从来不是一个好主意。相反,只需阅读一点并将其写在您的OutputStream上即可。 这是一个小示例,可以一次仅使用4KB内存上传文件。
File source = new File("mySourceFile.txt");
File target = new File("myTargetFile.txt");
int readByteCount = 0;
byte[] buffer = new byte[4096];
try(FileInputStream in = new FileInputStream(source);
FileOutputStream out = new FileOutputStream(target)) {
while((readByteCount = in.read(buffer)) != -1) {
out.write(buffer, 0, readByteCount);
}
}
答案 1 :(得分:0)
对于大文件,最好使用while循环将1024字节的字节读取到缓冲区中,然后将缓冲区写入服务器。此代码已经过5GB文件上传的测试。您需要相应地调整复制属性,即至少5GB如果您想尝试测试
spring.http.multipart.max-file-size=6000MB
spring.http.multipart.max-request-size=6000MB
这是使用spring框架编写的代码段。
@Override
public ResponseEntity<?> uploadFile(@RequestParam("file") MultipartFile multipartfile) {
ResponseEntity<String> response;
multipartfile.getOriginalFilename();
byte [] bufferedbytes= new byte[1024];
File file= new File("/home/david/Music/"+multipartfile.getOriginalFilename());
FileOutputStream outStream = null;
int count=0;
try {
BufferedInputStream fileInputStream= new BufferedInputStream(multipartfile.getInputStream());
outStream=new FileOutputStream(file);
while((count=fileInputStream.read(bufferedbytes))!=-1) {
outStream.write(bufferedbytes,0,count);
}
outStream.close();
} catch (IOException e) {
response= new ResponseEntity<String>("File failed to upload"+multipartfile.getOriginalFilename(),HttpStatus.PAYLOAD_TOO_LARGE);
return response;
}
response= new ResponseEntity<String>("File uploaded sucessifully"+multipartfile.getOriginalFilename(),HttpStatus.OK);
return response;
}