Comment convertir un fichier multipart en fichier?

90

Quelqu'un peut-il me dire quelle est la meilleure façon de convertir un fichier en plusieurs parties (org.springframework.web.multipart.MultipartFile) en fichier (java.io.File)?

Dans mon projet Web mvc de printemps, je reçois un fichier téléchargé en tant que fichier Multipart.Je dois le convertir en fichier (io), je peux donc appeler ce service de stockage d'images ( Cloudinary ) .Ils ne prennent que le type (File).

J'ai fait tellement de recherches mais j'ai échoué. Thnx

Amila Iddamalgoda
la source
5
Y a-t-il quelque chose qui vous empêche d'utiliser la méthode MultipartFile.transferTo()?
fajarkoe

Réponses:

192

Vous pouvez obtenir le contenu d'un MultipartFileen utilisant la getBytesméthode et vous pouvez écrire dans le fichier en utilisant Files.newOutputStream():

public void write(MultipartFile file, Path dir) {
    Path filepath = Paths.get(dir.toString(), file.getOriginalFilename());

    try (OutputStream os = Files.newOutputStream(filepath)) {
        os.write(file.getBytes());
    }
}

Vous pouvez également utiliser la méthode transferTo :

public void multipartFileToFile(
    MultipartFile multipart, 
    Path dir
) throws IOException {
    Path filepath = Paths.get(dir.toString(), multipart.getOriginalFilename());
    multipart.transferTo(filepath);
}
Petros Tsialiamanis
la source
7
J'ai utilisé la fonction transferTo mais je pense qu'il y a un problème. comme Il garde le fichier temporaire à conduire pour la machine locale.
Morez
@Ronnie J'ai le même problème. Avez-vous trouvé une solution de contournement?
Half Blood Prince
1
org.apache.commons.io.FileUtils.deleteQuietly (convFile.getParentFile ()); , cela devrait supprimer le fichier temporaire @Ronnie
kavinder
5
createNewFIle()est à la fois inutile et inutile ici. Vous êtes maintenant obligé new FileOutputStream()(via l'OS) à la fois de supprimer le fichier ainsi créé et d'en créer un nouveau.
Marquis of Lorne le
@Petros Tsialiamanis At-il une limite de taille de conversion de fichier en Java. Disons que j'utilise 3 Go de fichier.
Rohit
17

Bien que la réponse acceptée soit correcte, mais si vous essayez simplement de télécharger votre image sur cloudinary, il existe un meilleur moyen:

Map upload = cloudinary.uploader().upload(multipartFile.getBytes(), ObjectUtils.emptyMap());

Où multipartFile est votre org.springframework.web.multipart.MultipartFile .

Heisenberg
la source
17

petite correction sur le post @PetrosTsialiamanis, new File( multipart.getOriginalFilename())cela créera un fichier dans l'emplacement du serveur où vous rencontrerez parfois des problèmes d'autorisation d'écriture pour l'utilisateur, il n'est pas toujours possible de donner l'autorisation d'écriture à chaque utilisateur qui effectue une action. System.getProperty("java.io.tmpdir")créera un répertoire temporaire dans lequel votre fichier sera créé correctement. De cette façon, vous créez un dossier temporaire, où le fichier est créé, plus tard, vous pouvez supprimer le fichier ou le dossier temporaire.

public  static File multipartToFile(MultipartFile multipart, String fileName) throws IllegalStateException, IOException {
    File convFile = new File(System.getProperty("java.io.tmpdir")+"/"+fileName);
    multipart.transferTo(convFile);
    return convFile;
}

mettez cette méthode dans votre utilité commune et utilisez-la comme par exemple. Utility.multipartToFile(...)

Swadeshi
la source
8

Vous pouvez également utiliser la bibliothèque Apache Commons IO et la classe FileUtils . Si vous utilisez maven, vous pouvez le charger en utilisant la dépendance ci-dessus.

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

La source de l'enregistrement MultipartFile sur le disque.

File file = new File(directory, filename);

// Create the file using the touch method of the FileUtils class.
// FileUtils.touch(file);

// Write bytes from the multipart file to disk.
FileUtils.writeByteArrayToFile(file, multipartFile.getBytes());
George Siggouroglou
la source
FileUtils.touch()est à la fois inutile et inutile ici. Vous êtes maintenant obligé new FileOutputStream()(via l'OS) à la fois de supprimer le fichier ainsi créé et d'en créer un nouveau.
Marquis of Lorne
Merci pour votre commentaire. J'ai vérifié la source de la méthode FileUtils.writeByteArrayToFile. Je pense que cette méthode ne recrée pas le fichier au cas où il existe (version 2.4). L'objet multipartFile comprend les octets du fichier téléchargé que nous voulons stocker quelque part dans le système de fichiers. Mon but est de stocker ces octets dans un emplacement préféré. La seule raison pour laquelle je garde la méthode FileUtils.touch est de préciser qu'il s'agit d'un nouveau fichier. FileUtils.writeByteArrayToFile crée le fichier (et le chemin complet) au cas où il n'existe pas, donc FileUtils.touch n'est pas requis.
George Siggouroglou
7

MultipartFile.transferTo (File) est bien, mais n'oubliez pas de nettoyer le fichier temporaire après tout.

// ask JVM to ask operating system to create temp file
File tempFile = File.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_POSTFIX);

// ask JVM to delete it upon JVM exit if you forgot / can't delete due exception
tempFile.deleteOnExit();

// transfer MultipartFile to File
multipartFile.transferTo(tempFile);

// do business logic here
result = businessLogic(tempFile);

// tidy up
tempFile.delete();

Consultez le commentaire de Razzlero sur File.deleteOnExit () exécuté à la sortie de la JVM (ce qui peut être extrêmement rare) ci-dessous.

andrej
la source
2
deleteOnExit(), il ne se déclenchera qu'à la fin de la JVM, il ne se déclenchera donc pas pendant les exceptions. Pour cette raison, vous devez être prudent deleteOnExit()lorsque vous utilisez des applications de longue durée telles que des applications serveur. Pour les applications serveur, la JVM se fermera rarement. Vous devez donc faire attention à ne pas deleteOnExit()provoquer de fuites de mémoire. La JVM a besoin de garder une trace de tous les fichiers qu'elle doit supprimer à la sortie qui ne sont pas effacés car la JVM ne s'arrête pas.
Razzlero
@Razzlero merci d'avoir signalé qu'il ne supprime les fichiers qu'à la sortie de JVM. Cependant, ce n'est pas une fuite de mémoire, cela fonctionne comme prévu.
andrej
5
  private File convertMultiPartToFile(MultipartFile file ) throws IOException
    {
        File convFile = new File( file.getOriginalFilename() );
        FileOutputStream fos = new FileOutputStream( convFile );
        fos.write( file.getBytes() );
        fos.close();
        return convFile;
    }
sachintha hewawasam
la source
donnant cette exception java.io.FileNotFoundException: multipdf.pdf (Autorisation refusée)
Navnath Adsul
1

Vous pouvez accéder au fichier temporaire dans Spring en effectuant un cast si la classe de l'interface MultipartFileest CommonsMultipartFile.

public File getTempFile(MultipartFile multipartFile)
{
    CommonsMultipartFile commonsMultipartFile = (CommonsMultipartFile) multipartFile;
    FileItem fileItem = commonsMultipartFile.getFileItem();
    DiskFileItem diskFileItem = (DiskFileItem) fileItem;
    String absPath = diskFileItem.getStoreLocation().getAbsolutePath();
    File file = new File(absPath);

    //trick to implicitly save on disk small files (<10240 bytes by default)
    if (!file.exists()) {
        file.createNewFile();
        multipartFile.transferTo(file);
    }

    return file;
}

Pour se débarrasser de l'astuce avec des fichiers de moins de 10240 octets, la maxInMemorySizepropriété peut être définie sur 0 dans la @Configuration @EnableWebMvcclasse. Après cela, tous les fichiers téléchargés seront stockés sur le disque.

@Bean(name = "multipartResolver")
    public CommonsMultipartResolver createMultipartResolver() {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setDefaultEncoding("utf-8");
        resolver.setMaxInMemorySize(0);
        return resolver;
    }
Alex78191
la source
2
createNewFIle()est à la fois inutile et inutile ici. Vous êtes maintenant obligé new FileOutputStream()(via l'OS) à la fois de supprimer le fichier ainsi créé et d'en créer un nouveau.
Marquis of Lorne
@EJP oui, c'était inutile, maintenant je corrige cette erreur commise lors de l'édition. Mais createNewFIle () n'est pas un gaspillage, car si CommonsMultipartFile est inférieur à 10240 octets, le fichier dans le système de fichiers n'est pas créé. Ainsi, un nouveau fichier avec un nom unique (j'ai utilisé le nom de DiskFileItem) devrait être créé dans le FS.
Alex78191
@ Alex78191 Ce que vous entendez par enregistrer implicitement sur le disque de petits fichiers (<10240 octets par défaut). Y a-t-il quand même pour augmenter la limite
Anand Tagore
@AnandTagore Je veux dire que les moins de 10240 octets de MultipartFile ne sont pas enregistrés dans le système de fichiers, donc les fichiers doivent être créés manuellement.
Alex78191
0

La réponse d'Alex78191 a fonctionné pour moi.

public File getTempFile(MultipartFile multipartFile)
{

CommonsMultipartFile commonsMultipartFile = (CommonsMultipartFile) multipartFile;
FileItem fileItem = commonsMultipartFile.getFileItem();
DiskFileItem diskFileItem = (DiskFileItem) fileItem;
String absPath = diskFileItem.getStoreLocation().getAbsolutePath();
File file = new File(absPath);

//trick to implicitly save on disk small files (<10240 bytes by default)

if (!file.exists()) {
    file.createNewFile();
    multipartFile.transferTo(file);
}

return file;
}

Pour télécharger des fichiers d'une taille supérieure à 10240 octets, veuillez modifier maxInMemorySize dans multipartResolver à 1 Mo.

<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- setting maximum upload size t 20MB -->
<property name="maxUploadSize" value="20971520" />
<!-- max size of file in memory (in bytes) -->
<property name="maxInMemorySize" value="1048576" />
<!-- 1MB --> </bean>
Anand Tagore
la source
maxInMemorySizen'a rien à voir avec la limitation de la taille de téléchargement des fichiers. La taille de téléchargement du fichier est définie par la maxUploadSizepropriété.
Alex78191
Pour se débarrasser de l'astuce avec des fichiers de moins de 10240 octets, maxInMemorySizeprop peut être défini sur 0.
Alex78191
@ Alex78191 J'ai changé cela et cela a fonctionné pour moi. J'avais utilisé votre code pour convertir le fichier. J'ai donc changé les propriétés dans le fichier applicationcontext.xml pour se débarrasser des limitations de mémoire. Et il fonctionne !!!
Anand Tagore
Lors de la création d'un fichier à partir d'un fichier en plusieurs parties, il doit être conservé en mémoire. Donc, pour cela, je dois augmenter le maxInMemorySize.
Anand Tagore
0

si vous ne souhaitez pas utiliser MultipartFile.transferTo (). Vous pouvez écrire un fichier comme celui-ci

    val dir = File(filePackagePath)
    if (!dir.exists()) dir.mkdirs()

    val file = File("$filePackagePath${multipartFile.originalFilename}").apply {
        createNewFile()
    }

    FileOutputStream(file).use {
        it.write(multipartFile.bytes)
    }
Artem Botnev
la source