由于工作需要,涉及到文件类型的转化,实际上MultipartFile有方法可以直接转化为InputStream,但是并没有办法可以从InputStream直接转化为MultipartFile。
网上的资料大概看了下,有两种简单的方案CommonsMultipartFile和MockMultipartFile,不过对我来说都不适用,因为我不能添加依赖。
我决定先看下MultipartFile怎么转化成InputStream。
public class CommonsMultipartFile implements MultipartFile, Serializable {
protected static final Log logger = LogFactory.getLog(CommonsMultipartFile.class);
private final FileItem fileItem;
private final long size;
private boolean preserveFilename = false;
public CommonsMultipartFile(FileItem fileItem) {
this.fileItem = fileItem;
this.size = this.fileItem.getSize();
}
很尴尬,进到getInputStream()方法中直接看到了CommonsMultipartFile实现类,看来我的起步依赖直接就包含了这个实现类,不用引入了,那接下来的事情就好办了,不过我还是决定继续往后看看
//CommonsMultipartFile中的方法
public InputStream getInputStream() throws IOException {
if (!this.isAvailable()) {
throw new IllegalStateException("File has been moved - cannot be read again");
} else {
InputStream inputStream = this.fileItem.getInputStream();
return inputStream != null ? inputStream : StreamUtils.emptyInput();
}
}
可以看出,压力来到了fileItem这边,继续往后找,找到一个FileItem实现类
public class DiskFileItem implements FileItem {
public static final String SERIALIZABLE_PROPERTY = DiskFileItem.class.getName() + ".serializable";
private static final long serialVersionUID = 2237570099615271025L;
public static final String DEFAULT_CHARSET = "ISO-8859-1";
private static final String UID = UUID.randomUUID().toString().replace('-', '_');
private static final AtomicInteger COUNTER = new AtomicInteger(0);
private String fieldName;
private final String contentType;
private boolean isFormField;
private final String fileName;
private long size = -1L;
private final int sizeThreshold;
private final File repository;
private byte[] cachedContent;
private transient DeferredFileOutputStream dfos;
private transient File tempFile;
private File dfosFile;
private FileItemHeaders headers;
public DiskFileItem(String fieldName, String contentType, boolean isFormField, String fileName, int sizeThreshold, File repository) {
this.fieldName = fieldName;
this.contentType = contentType;
this.isFormField = isFormField;
this.fileName = fileName;
this.sizeThreshold = sizeThreshold;
this.repository = repository;
}
虽然这个FileItem类有构造方法,不过。。里面有一些属性确实没看明白是干啥的。然后继续往后
public InputStream getInputStream() throws IOException {
if (!this.isInMemory()) {
return new FileInputStream(this.dfos.getFile());
} else {
if (this.cachedContent == null) {
this.cachedContent = this.dfos.getData();
}
return new ByteArrayInputStream(this.cachedContent);
}
}
public byte[] getData() {
return this.memoryOutputStream != null ? this.memoryOutputStream.toByteArray() : null;
}
public synchronized byte[] toByteArray() {
int remaining = this.count;
if (remaining == 0) {
return EMPTY_BYTE_ARRAY;
} else {
byte[] newbuf = new byte[remaining];
int pos = 0;
Iterator var4 = this.buffers.iterator();
while(var4.hasNext()) {
byte[] buf = (byte[])var4.next();
int c = Math.min(buf.length, remaining);
System.arraycopy(buf, 0, newbuf, pos, c);
pos += c;
remaining -= c;
if (remaining == 0) {
break;
}
}
return newbuf;
}
最终看起来这个toByteArray()方法是个干活的,干的活大概是把文件转成byte[]数组,那实际上有两种解决方案了,一种就是直接用CommonsMultipartFile(这个地方我看了网上才知道有工厂类可以创建),一种是自己转化成byte[]数组,然后在转化成CommonsMultipartFile
public void testOSSServiceImport(){
File file = new File("test.png");
DiskFileItem fileItem = (DiskFileItem) new DiskFileItemFactory().createItem("file",
MediaType.ALL_VALUE, true, file.getName());
try (InputStream input = new FileInputStream(file); OutputStream os = fileItem.getOutputStream()) {
IOUtils.copy(input, os);
} catch (Exception e) {
throw new IllegalArgumentException("Invalid file: " + e, e);
}
MultipartFile multi = new CommonsMultipartFile(fileItem);
}
这个是参考网上的CommonsMultipartFile用法
/**
* 获取封装得MultipartFile
*
* @param inputStream inputStream
* @param fileName fileName
* @return MultipartFile
*/
public MultipartFile getMultipartFile(InputStream inputStream, String fileName) {
FileItem fileItem = createFileItem(inputStream, fileName);
//CommonsMultipartFile是feign对multipartFile的封装,但是要FileItem类对象
return new CommonsMultipartFile(fileItem);
}
/**
* FileItem类对象创建
*
* @param inputStream inputStream
* @param fileName fileName
* @return FileItem
*/
public FileItem createFileItem(InputStream inputStream, String fileName) {
FileItemFactory factory = new DiskFileItemFactory(16, null);
String textFieldName = "file";
FileItem item = factory.createItem(textFieldName, MediaType.MULTIPART_FORM_DATA_VALUE, true, fileName);
int bytesRead = 0;
byte[] buffer = new byte[10 * 1024 * 1024];
OutputStream os = null;
//使用输出流输出输入流的字节
try {
os = item.getOutputStream();
while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
inputStream.close();
} catch (IOException e) {
log.error("Stream copy exception", e);
throw new IllegalArgumentException("文件上传失败");
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
log.error("Stream close exception", e);
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.error("Stream close exception", e);
}
}
}
return item;
}
这个是用byte[]数组的转化