赞
踩
开发背景:系统需添加一个云盘模块,有文件上传功能,同步上传大文件传输速度很慢,用户等待时间过长,采取了异步上传。发现有时存在系统找不到指定的文件,导致上传失败的问题。
发现问题:网络查找发现是springboot文件上传,会创建临时目录保存临时文件,处理完后会清除。
报错信息如下:
- java.io.FileNotFoundException: C:\Users\***\work\Catalina\localhost\ROOT\upload_22e2506c_3d38_4755_8ea1_f81b600f8c2e_00000005.tmp (系统找不到指定的文件。)
- at java.io.FileInputStream.open0(Native Method)
- at java.io.FileInputStream.open(FileInputStream.java:195)
- at java.io.FileInputStream.<init>(FileInputStream.java:138)
- at org.apache.tomcat.util.http.fileupload.disk.DiskFileItem.getInputStream(DiskFileItem.java:194)
- at org.apache.catalina.core.ApplicationPart.getInputStream(ApplicationPart.java:100)
- at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.getInputStream(StandardMultipartHttpServletRequest.java:296)
- at cn.com.teacher.service.impl.MyCloudStorageServiceImpl.saveFile(MyCloudStorageServiceImpl.java:75)
- at cn.com.teacher.service.impl.MyCloudStorageServiceImpl.lambda$saveCloudStorageFile$0(MyCloudStorageServiceImpl.java:64)
- at java.util.concurrent.CompletableFuture$AsyncRun.run$$$capture(CompletableFuture.java:1626)
- at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java)
- at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
- at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
- at java.lang.Thread.run(Thread.java:748)
之前代码:
- CompletableFuture.runAsync(()->{
- saveFile(MultipartFile);
- },executor);
现在代码:
- InputStream inputStream = multipartFile.getInputStream();
- CompletableFuture.runAsync(()->{
- //传递流
- saveFile(inputStream);
- },executor);
解决方案:改为传递流
出现地点:需要把文件上传到OSS上,流关闭,后面需生成文件的md5值,工具类,也需要InputStream,里面也把流关闭,出现了问题。
发现问题:InputStream只能读取一次,如果需要重复读取,需要转换或者存储。
报错信息:java.io.IOException: Stream Closed
解决方案:InputStream不支持重置,但是它的子类ByteArrayInputStream支持
- //InputStream代码
-
- public synchronized void mark(int readlimit) {}
-
-
- public synchronized void reset() throws IOException {
- throw new IOException("mark/reset not supported");
- }
-
-
- public boolean markSupported() {
- return false;
- }
- //ByteArrayInputStream代码
-
- protected int mark = 0;
-
- //是否支持重置
- public boolean markSupported() {
- return true;
- }
-
- //定点,下次从哪里重新读取
- public void mark(int readAheadLimit) {
- mark = pos;
- }
-
- //重置到定点位置后,可重新读取
- public synchronized void reset() {
- pos = mark;
- }

把InputStream转换未ByteArrayInputStream,第二次使用前使用重置方法即可
byteArrayInputStream.reset();
下面转换代码取自:InputStream重复使用小技巧_I_am_zz.的博客-CSDN博客_inputstream重复使用
- public static ByteArrayInputStream toByteArrayInputStream(InputStream inputStream) throws IOException {
- if (inputStream instanceof ByteArrayInputStream) {
- return (ByteArrayInputStream) inputStream;
- }
-
- try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
- BufferedInputStream br = new BufferedInputStream(inputStream);
- byte[] b = new byte[1024];
- for (int c; (c = br.read(b)) != -1; ) {
- bos.write(b, 0, c);
- }
- // 主动告知回收
- b = null;
- br.close();
- inputStream.close();
- return new ByteArrayInputStream(bos.toByteArray());
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。