Java:InputStream转换为多部分文件,结果文件为空

我正在一个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.");
    }

}
上一篇:java-Spring org.springframework.web.multipart.support.MissingServletRequestPartException,必需的请求部分“文件”


下一篇:php-多部分/混合电子邮件表单数据中md5的用途