今天做了一个小功能,大概是对前端传回来的MultipartFile中的脚本文件进行解析处理,处理后再封装成MultipartFile对象传递给其它接口继续调用,遇到一些坑,简单记录一下。
1.读取并处理MultipartFile中的脚本内容:
Reader reader = new InputStreamReader(multipartFile.getInputStream(), StandardCharsets.UTF_8);
BufferedReader bufferedReader = new BufferedReader(reader);
StringBuilder stringBuilder = new StringBuilder();
String lineStr;
//逐行读取
while (null != (lineStr = bufferedReader.readLine())) {
//TODO 按你的需求处理
stringBuilder.append(lineStr).append("\n");
}
String scriptContent = stringBuilder.toString();
这样我们就得到了处理后的String结果,问题是这个结果如何转换回MultipartFile?
在网上查询很多使用的是如下方案:
通过IO读取String(或将String写入文件),再使用MockMultipartFile方法将File转换成MultipartFile。
MultipartFile multipartFile = new MockMultipartFile(pdfFile.getName(),fileInputStream);
考虑后发现实际不可行,原因如下:
- 在服务器高并发情况下,生成大量小文件会导致服务器inode被打满,另外生成文件还需要考虑命名处理防止重名。
- MockMultipartFile这个方法看起来很方便,实际上这个方法是spring-test中提供的,生产环境根本不会打包test。
所以我决定干脆自己实现一下MultipartFile接口,实际并不复杂,如下:
//先把string转换成字节数组
byte[] scriptByte = scriptContent.getBytes(StandardCharsets.UTF_8);
return new MultipartFile() {
@Override
public String getName() {
//直接使用了原文件的属性
return multipartFile.getName();
}
@Override
public String getOriginalFilename() {
//直接使用了原文件的属性
return multipartFile.getOriginalFilename();
}
@Override
public String getContentType() {
//直接使用了原文件的属性
return multipartFile.getContentType();
}
@Override
public boolean isEmpty() {
return StringUtil.isEmpty(scriptContent);
}
@Override
public long getSize() {
return scriptContent.length();
}
@Override
public byte[] getBytes() {
return scriptByte;
}
@Override
public InputStream getInputStream() {
return new ByteArrayInputStream(scriptByte);
}
@Override
public void transferTo(File file) throws IOException, IllegalStateException {
new FileOutputStream(file).write(scriptByte);
}
};