我正在一个Java应用程序中尝试从下载的InputStream中创建一个Multipart文件.不幸的是,它无法正常工作,并且Multipart文件为空.在将文件复制到Multipart之前,我检查了磁盘上savedFile的大小,它具有正确的大小,属性和内容.
我在转换中做错了什么,没有堆栈跟踪,因为我正在捕获它.
代码:
// InputStream contains file data.
byte[] bytes = IOUtils.toByteArray(inputStream);
File file = new File(msg + "temp");
if (file.exists() && file.isDirectory()) {
OutputStream outputStream = new FileOutputStream(new File(msg + "temp" + "/" +
groupAttachments.getFileName()));
outputStream.write(bytes);
outputStream.close();
}
java.io.File savedFile = new java.io.File(msg + "temp" + "/" +
groupAttachments.getFileName());
DiskFileItem fileItem = new DiskFileItem("file", "text/plain", false,
savedFile.getName(), (int) savedFile.length(), savedFile.getParentFile());
fileItem.getOutputStream();
MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
System.out.println("Saved file size is "+savedFile.length());
if (multipartFile.isEmpty()) {
System.out.println("Dropbox uploaded multipart file is empty");
} else {
System.out.println("Multipart file is not empty.");
}
this.dropboxTask.insertFile(multipartFile, "",
savedPersonalNoteObject.getNoteid(), (long) 0, true);
Path path = Paths.get(msg + "temp" + "/" + groupAttachments.getFileName());
控制台输出:
Multipart file is not empty
Bytes are not null
File path is /My Group
Input stream is not null
Saved file size is 4765
Dropbox uploaded multipart file is empty
Multipart file is empty
Bytes are not null
转换中我在做什么错?你能帮忙的话,我会很高兴.非常感谢.
解决方法:
DiskFileItem使用DeferredFileOutputStream,后者使用内存中的字节数组,该数组仅在实际传输字节时才填充.
由于文件是直接使用的,实际上没有字节被复制,
字节数组永远不会被填充.亲自查看源代码:
源代码CommonsMultipartFile
源代码DiskFileItem
源代码DeferredFileOutputStream
因此,不只是调用fileItem.getOutputStream();,而是传输字节以填充内存中的字节数组:
try (OutputStream out = fileItem.getOutputStream();
InputStream in = Files.newInputStream(file.toPath())) {
IOUtils.copy(in, dfos);
}
然后tranferTo调用将起作用.
仅移动文件似乎有点麻烦:CommonsMultipartFile仅在transferTo方法中调用fileItem.write((File)dest).
下面是两个测试用例,一个使用DiskFileItem,另一个使用LocalFileItem.下面进一步显示LocalFileItem的代码.
我使用依赖项org.springframework:spring-web:4.2.2.RELEASE,commons-fileupload:commons-fileupload:1.3.1和junit:junit:4.12
测试类CommonMp:
import static org.junit.Assert.*;
import java.io.*;
import java.nio.charset.*;
import java.nio.file.*;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
public class CommonMp {
private final Charset CS = StandardCharsets.UTF_8;
@Test
public void testLocalMp() {
Path testInputFile = null, testOutputFile = null;
try {
testInputFile = prepareInputFile();
LocalFileItem lfi = new LocalFileItem(testInputFile);
CommonsMultipartFile cmf = new CommonsMultipartFile(lfi);
System.out.println("Empty: " + cmf.isEmpty());
testOutputFile = testInputFile.getParent().resolve("testMpOutput.txt");
cmf.transferTo(testOutputFile.toFile());
System.out.println("Size: " + cmf.getSize());
printOutput(testOutputFile);
} catch (Exception e) {
e.printStackTrace();
fail();
} finally {
deleteSilent(testInputFile, testOutputFile);
}
}
@Test
public void testMp() {
Path testInputFile = null, testOutputFile = null;
try {
testInputFile = prepareInputFile();
DiskFileItem di = new DiskFileItem("file", "text/plain", false, testInputFile.getFileName().toString(),
(int) Files.size(testInputFile), testInputFile.getParent().toFile());
try (OutputStream out = di.getOutputStream();
InputStream in = Files.newInputStream(testInputFile)) {
IOUtils.copy(in, out);
}
CommonsMultipartFile cmf = new CommonsMultipartFile(di);
System.out.println("Size: " + cmf.getSize());
testOutputFile = testInputFile.getParent().resolve("testMpOutput.txt");
cmf.transferTo(testOutputFile.toFile());
printOutput(testOutputFile);
} catch (Exception e) {
e.printStackTrace();
fail();
} finally {
deleteSilent(testInputFile, testOutputFile);
}
}
private Path prepareInputFile() throws IOException {
Path tmpDir = Paths.get(System.getProperty("java.io.tmpdir"));
Path testInputFile = tmpDir.resolve("testMpinput.txt");
try (OutputStream out = Files.newOutputStream(testInputFile)){
out.write("Just a test.".getBytes(CS));
}
return testInputFile;
}
private void printOutput(Path p) throws IOException {
byte[] outBytes = Files.readAllBytes(p);
System.out.println("Output: " + new String(outBytes, CS));
}
private void deleteSilent(Path... paths) {
for (Path p : paths) {
try { if (p != null) p.toFile().delete(); } catch (Exception ignored) {}
}
}
}
自定义LocalFileItem类,YMMV!
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemHeaders;
public class LocalFileItem implements FileItem {
private static final long serialVersionUID = 2467880290855097332L;
private final Path localFile;
public LocalFileItem(Path localFile) {
this.localFile = localFile;
}
@Override
public void write(File file) throws Exception {
Files.move(localFile, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
@Override
public long getSize() {
// Spring's CommonsMultipartFile caches the file size and uses it to determine availability.
long size = -1L;
try {
size = Files.size(localFile);
} catch (IOException ignored) {}
return size;
}
@Override
public void delete() {
localFile.toFile().delete();
}
/* *** properties and unsupported methods *** */
private FileItemHeaders headers;
private String contentType;
private String fieldName;
private boolean formField;
@Override
public FileItemHeaders getHeaders() {
return headers;
}
@Override
public void setHeaders(FileItemHeaders headers) {
this.headers = headers;
}
@Override
public InputStream getInputStream() throws IOException {
throw new IOException("Only method write(File) is supported.");
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
@Override
public String getContentType() {
return contentType;
}
@Override
public String getName() {
return localFile.getFileName().toString();
}
@Override
public boolean isInMemory() {
return false;
}
@Override
public byte[] get() {
throw new RuntimeException("Only method write(File) is supported.");
}
@Override
public String getString(String encoding)
throws UnsupportedEncodingException {
throw new RuntimeException("Only method write(File) is supported.");
}
@Override
public String getString() {
throw new RuntimeException("Only method write(File) is supported.");
}
@Override
public String getFieldName() {
return fieldName;
}
@Override
public void setFieldName(String name) {
this.fieldName = name;
}
@Override
public boolean isFormField() {
return formField;
}
@Override
public void setFormField(boolean state) {
this.formField = state;
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new IOException("Only method write(File) is supported.");
}
}