一.需求
现在有个需求,要通过InputStream流先去判断文件类型,然后再上传文件,这样就会用到两次InputStream。
二.问题
这个功能之前的同事已经做了一版,一直以为是正常的,毕竟都很久了,但是我用的时候发现上传的文件总是空的,只能去仔细看下代码了。
三.排查
try (InputStream in = inputStream) {
//检验文件
CheckFileUtil.checkFile(inputStream, FileUtil.extName(filename));
LoggerFactory.getLogger(this.getClass()).info("上传文件的文件名="+filename);
//上传文件
String filePathURL = saveToDisk(in, FileUtil.extName(filename));
FileInfo fileInfo = new FileInfo();
fileInfo.setId(RandomUtil.simpleUUID());
fileInfo.setFileName(filename);
fileInfo.setFileType(FileUtil.extName(filename));
之前的代码逻辑是用原来的inputStream去校验,然后用赋值后的in去上传文件,开始看到这里也没发现有什么问题,感觉很正常。
只能去加日志,打断点调试了,最终发现在校验文件之后,不管是inputStream还是in都是空的了,恍然大悟。由于流读过一次就不能再读了。
四.解决
开始想着去复制一遍这个流就行了,查了下才知道不行,InputStream对象本身不能复制,它也没有实现Cloneable接口。
那就先用byte[]去存储,然后用的时候在转换。调整后的代码
public static byte[] readInputStreamToByteArray(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
}
return byteArrayOutputStream.toByteArray();
}
@Override
public FileInfo upload(String filename, Long size, InputStream inputStream) {
try (InputStream in = inputStream) {
byte[] bytes = readInputStreamToByteArray(in);
//检验文件
CheckFileUtil.checkFile(new ByteArrayInputStream(bytes), FileUtil.extName(filename));
LoggerFactory.getLogger(this.getClass()).info("上传文件的文件名="+filename);
//上传文件
String filePathUrl = saveToDisk(new ByteArrayInputStream(bytes), FileUtil.extName(filename));
但是这种明显只适用于文件不大的时候,不知道如果文件较大的情况下,该怎么进一步优化,先记录下,后面遇到了再补充