80

Is there any way to convert a File object to MultiPartFile? So that I can send that object to methods that accept the objects of MultiPartFile interface?

File myFile = new File("/path/to/the/file.txt")

MultiPartFile ....?

def (MultiPartFile file) {
  def is = new BufferedInputStream(file.getInputStream())
  //do something interesting with the stream
}
Georgios Syngouroglou
  • 18,813
  • 9
  • 90
  • 92
birdy
  • 9,286
  • 24
  • 107
  • 171
  • 2
    You should be able to write your own class which implements [`FileItem`](http://commons.apache.org/proper/commons-fileupload/apidocs/org/apache/commons/fileupload/FileItem.html) but that takes an actual `File` to delegate to, then pass this `FileItem` instance to the constructor of [`CommonsMultipartFile`](http://static.springsource.org/spring/docs/1.2.x/api/org/springframework/web/multipart/commons/CommonsMultipartFile.html) which implements `MultiPartFile` – tim_yates May 20 '13 at 11:38
  • I've made a class that implements FileItem but I don't know how to implement all the methods of that interface. I've created a variable in this class which is `File myFile`. Should I just implement `getinputStream()` and `getOutputStream()`? – birdy May 20 '13 at 22:06
  • in particular, I don't know what you mean by this "but that takes an actual File to delegate to". This is what I have so far: https://gist.github.com/birdy101/5616009 – birdy May 20 '13 at 22:07
  • [Something like this](https://gist.github.com/timyates/eb5d394ab5e87a3496ce). Not tested it, but as you can see for methods where it's possible, I call methods on the `artifact`. You should be able to construct it with `new StoredFile( artifact: new File( '/path/to/file' ) )`... Fingers crossed it works... – tim_yates May 22 '13 at 08:55

12 Answers12

65

MockMultipartFile exists for this purpose. As in your snippet if the file path is known, the below code works for me.

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.springframework.mock.web.MockMultipartFile;

Path path = Paths.get("/path/to/the/file.txt");
String name = "file.txt";
String originalFileName = "file.txt";
String contentType = "text/plain";
byte[] content = null;
try {
    content = Files.readAllBytes(path);
} catch (final IOException e) {
}
MultipartFile result = new MockMultipartFile(name,
                     originalFileName, contentType, content);
Arun
  • 791
  • 6
  • 10
32
File file = new File("src/test/resources/input.txt");
FileInputStream input = new FileInputStream(file);
MultipartFile multipartFile = new MockMultipartFile("file",
            file.getName(), "text/plain", IOUtils.toByteArray(input));
SkyWalker
  • 28,384
  • 14
  • 74
  • 132
Anoop George
  • 742
  • 6
  • 6
24
MultipartFile multipartFile = new MockMultipartFile("test.xlsx", new FileInputStream(new File("/home/admin/test.xlsx")));

This code works fine for me. May be you can have a try.

SkyWalker
  • 28,384
  • 14
  • 74
  • 132
user8840900
  • 257
  • 2
  • 3
22

In my case, the

fileItem.getOutputStream();

wasn't working. Thus I made it myself using IOUtils,

File file = new File("/path/to/file");
FileItem fileItem = new DiskFileItem("mainFile", Files.probeContentType(file.toPath()), false, file.getName(), (int) file.length(), file.getParentFile());

try {
    InputStream input = new FileInputStream(file);
    OutputStream os = fileItem.getOutputStream();
    IOUtils.copy(input, os);
    // Or faster..
    // IOUtils.copy(new FileInputStream(file), fileItem.getOutputStream());
} catch (IOException ex) {
    // do something.
}

MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
Georgios Syngouroglou
  • 18,813
  • 9
  • 90
  • 92
16

This is a solution without creating manually a file on disc :

MultipartFile fichier = new MockMultipartFile("fileThatDoesNotExists.txt",
            "fileThatDoesNotExists.txt",
            "text/plain",
            "This is a dummy file content".getBytes(StandardCharsets.UTF_8));
ihebiheb
  • 3,673
  • 3
  • 46
  • 55
  • Hi, I'm trying this but with .xlsx extension and contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet". It's not working for me, please any help? – rubydio Sep 22 '20 at 11:34
  • Sorry I did not try it on excel files. I don't have an idea on how to do it. Maybe you should open another thread for it – ihebiheb Sep 22 '20 at 12:54
7
File file = new File("src/test/resources/validation.txt");
DiskFileItem fileItem = new DiskFileItem("file", "text/plain", false, file.getName(), (int) file.length() , file.getParentFile());
fileItem.getOutputStream();
MultipartFile multipartFile = new CommonsMultipartFile(fileItem);

You need the following to prevent NPE.

fileItem.getOutputStream();

Also, you need to copy the file content to fileItem so that file won't be empty

new FileInputStream(f).transferTo(item.getOutputStream());

gtiwari333
  • 24,554
  • 15
  • 75
  • 102
despot
  • 7,167
  • 9
  • 44
  • 63
7

Solution without Mocking class, Java9+ and Spring only.

FileItem fileItem = new DiskFileItemFactory().createItem("file",
    Files.probeContentType(file.toPath()), false, file.getName());

try (InputStream in = new FileInputStream(file); OutputStream out = fileItem.getOutputStream()) {
    in.transferTo(out);
} catch (Exception e) {
    throw new IllegalArgumentException("Invalid file: " + e, e);
}

CommonsMultipartFile multipartFile = new CommonsMultipartFile(fileItem);
MariuszS
  • 30,646
  • 12
  • 114
  • 155
  • 1
    Thank you for solving this with a real CommonsMultipartFile. This is satisfactory for production use. – Planky Apr 29 '20 at 22:21
  • you will need maven dependency "Apache Commons FileUpload" https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload/1.4 – Mohamed Adel Dec 12 '21 at 23:38
  • CommonsMultipartFile multipartFile line is giving outofmemory error. Any solution for that @MariuszS – Swathi Nov 19 '22 at 01:33
6

You can make your own implementation of MultipartFile. For example:

public class JavaFileToMultipartFile implements MultipartFile {

private final File file;

public TPDecodedMultipartFile(File file) {
    this.file = file;
}

@Override
public String getName() {
    return file.getName();
}

@Override
public String getOriginalFilename() {
    return file.getName();
}

@Override
public String getContentType() {
    try {
        return Files.probeContentType(file.toPath());
    } catch (IOException e) {
        throw new RuntimeException("Error while extracting MIME type of file", e);
    }
}

@Override
public boolean isEmpty() {
    return file.length() == 0;
}

@Override
public long getSize() {
    return file.length();
}

@Override
public byte[] getBytes() throws IOException {
    return Files.readAllBytes(file.toPath());
}

@Override
public InputStream getInputStream() throws IOException {
    return new FileInputStream(file);
}

@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
    throw new UnsupportedOperationException();
}
}
I.Yuldoshev
  • 108
  • 1
  • 5
  • 1
    This is the most elegant solution. It works without having to import the spring boot test package. My applications stopped working when I upgraded to Spring Boot 3 since CommonsMultipartFile is no longer supported in Spring Framework 6. – Lukuluba Jan 15 '23 at 10:50
4

If you can't import MockMultipartFile using

import org.springframework.mock.web.MockMultipartFile;

you need to add the below dependency into pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
fcdt
  • 2,371
  • 5
  • 14
  • 26
eRobot
  • 107
  • 1
  • 7
2

It's working for me:

File file = path.toFile();
String mimeType = Files.probeContentType(path);     

DiskFileItem fileItem = new DiskFileItem("file", mimeType, false, file.getName(), (int) file.length(),
            file.getParentFile());
fileItem.getOutputStream();
MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
SkyWalker
  • 28,384
  • 14
  • 74
  • 132
Purushottam Sadh
  • 1,087
  • 10
  • 5
1
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import org.apache.commons.io.IOUtils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

public static void main(String[] args) {
        convertFiletoMultiPart();
    }

    private static void convertFiletoMultiPart() {
        try {
            File file = new File(FILE_PATH);
            if (file.exists()) {
                System.out.println("File Exist => " + file.getName() + " :: " + file.getAbsolutePath());
            }
            FileInputStream input = new FileInputStream(file);
            MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain",
                    IOUtils.toByteArray(input));
            System.out.println("multipartFile => " + multipartFile.isEmpty() + " :: "
                    + multipartFile.getOriginalFilename() + " :: " + multipartFile.getName() + " :: "
                    + multipartFile.getSize() + " :: " + multipartFile.getBytes());
        } catch (IOException e) {
            System.out.println("Exception => " + e.getLocalizedMessage());
        }
    }

This worked for me.

Sidhajyoti
  • 59
  • 4
  • For the above code below is the dependencies for gradle. compile group: 'commons-fileupload', name: 'commons-fileupload', version: '1.3' compile group: 'org.springframework', name: 'spring-web', version: '3.0.4.RELEASE' compile group: 'org.springframework', name: 'spring-mock', version: '2.0.7' – Sidhajyoti Jun 18 '20 at 13:50
0

For gradle projects add - implementation group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.7.4'

Palak
  • 11
  • 1