Come convertire un file multipart in file?


90

Qualcuno può dirmi qual è il modo migliore per convertire un file multipart (org.springframework.web.multipart.MultipartFile) in file (java.io.File)?

Nel mio progetto web primaverile mvc ricevo il file caricato come file Multipart. Devo convertirlo in un File (io), quindi posso chiamare questo servizio di archiviazione delle immagini ( Cloudinary ). Prendono solo il tipo (File).

Ho fatto così tante ricerche ma non ci sono riuscito. Se qualcuno conosce un buon metodo standard per favore fatemelo sapere. Thnx


5
C'è qualcosa che ti impedisce di utilizzare il metodo MultipartFile.transferTo()?
fajarkoe

Risposte:


192

Puoi ottenere il contenuto di a MultipartFileutilizzando il getBytesmetodo e puoi scrivere sul file usando 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());
    }
}

Puoi anche utilizzare il metodo transferTo :

public void multipartFileToFile(
    MultipartFile multipart, 
    Path dir
) throws IOException {
    Path filepath = Paths.get(dir.toString(), multipart.getOriginalFilename());
    multipart.transferTo(filepath);
}

7
Ho usato transferTo Function ma sento che c'è un problema. come Mantiene il file temporaneo da guidare per la macchina locale.
Morez

@Ronnie Sto avendo lo stesso problema. Hai trovato qualche soluzione alternativa?
Principe Mezzosangue

1
org.apache.commons.io.FileUtils.deleteQuietly (convFile.getParentFile ()); , questo dovrebbe eliminare il file temporaneo @Ronnie
kavinder

5
createNewFIle()è sia inutile che dispendioso qui. Ora stai obbligando new FileOutputStream()(tramite il sistema operativo) sia a eliminare il file così creato che a crearne uno nuovo.
Marchese di Lorne,

@ Petros Tsialiamanis Ha limiti di dimensione per la conversione dei file in Java. Diciamo che sto usando 3 GB di file.
Rohit

17

Sebbene la risposta accettata sia corretta, ma se stai solo cercando di caricare la tua immagine su cloudinary, c'è un modo migliore:

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

Dove multipartFile è il tuo org.springframework.web.multipart.MultipartFile .


17

piccola correzione sul post di @PetrosTsialiamanis, new File( multipart.getOriginalFilename())questo creerà un file nella posizione del server dove a volte dovrai affrontare problemi di autorizzazione di scrittura per l'utente, non è sempre possibile dare il permesso di scrittura a ogni utente che esegue un'azione. System.getProperty("java.io.tmpdir")creerà la directory temporanea in cui il file verrà creato correttamente. In questo modo stai creando una cartella temporanea, dove viene creato il file, in seguito puoi eliminare il file o la cartella temporanea.

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;
}

metti questo metodo nella tua utilità comune e usalo come per es. Utility.multipartToFile(...)


8

Puoi anche utilizzare la libreria I / O di Apache Commons e la classe FileUtils . Nel caso tu stia usando Maven, puoi caricarlo usando la dipendenza sopra.

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

La sorgente per il salvataggio su disco di MultipartFile.

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());

FileUtils.touch()è sia inutile che dispendioso qui. Ora stai obbligando new FileOutputStream()(tramite il sistema operativo) sia a eliminare il file così creato che a crearne uno nuovo.
Marchese di Lorne

Grazie per il tuo commento. Ho controllato l'origine del metodo FileUtils.writeByteArrayToFile. Penso che questo metodo non stia ricreando il file nel caso in cui esista (versione 2.4). L'oggetto multipartFile include i byte del file caricato che vogliamo memorizzare da qualche parte nel filesystem. Il mio scopo è memorizzare questi byte in una posizione preferita. L'unico motivo per cui mantengo il metodo FileUtils.touch è per chiarire che si tratta di un nuovo file. FileUtils.writeByteArrayToFile crea il file (e il percorso completo) nel caso non esista, quindi FileUtils.touch non è richiesto.
George Siggouroglou

7

MultipartFile.transferTo (File) è carino, ma non dimenticare di pulire il file temporaneo dopo tutto.

// 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();

Controlla il commento di Razzlero su File.deleteOnExit () eseguito all'uscita da JVM (che potrebbe essere estremamente raro) i dettagli di seguito.


2
deleteOnExit(), si attiverà solo quando la JVM termina, quindi non si attiverà durante le eccezioni. Per questo motivo è necessario prestare attenzione nell'utilizzo deleteOnExit()su applicazioni a esecuzione prolungata come le applicazioni server. Per le applicazioni server, la JVM verrà chiusa raramente. Quindi è necessario fare attenzione a deleteOnExit()causare perdite di memoria. La JVM deve tenere traccia di tutti i file che deve eliminare all'uscita che non vengono cancellati perché la JVM non viene terminata.
Razzlero

@ Razzlero grazie per aver sottolineato che elimina i file solo all'uscita da JVM. Tuttavia non è una perdita di memoria, funziona come previsto.
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;
    }

dando questa eccezione java.io.FileNotFoundException: multipdf.pdf (Autorizzazione negata)
Navnath Adsul

1

Puoi accedere a tempfile in Spring eseguendo il casting se la classe dell'interfaccia MultipartFileè 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;
}

Per sbarazzarsi del trucco con file inferiori a 10240 byte, la maxInMemorySizeproprietà può essere impostata a 0 in @Configuration @EnableWebMvcclasse. Dopodiché, tutti i file caricati verranno archiviati su disco.

@Bean(name = "multipartResolver")
    public CommonsMultipartResolver createMultipartResolver() {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setDefaultEncoding("utf-8");
        resolver.setMaxInMemorySize(0);
        return resolver;
    }

2
createNewFIle()è sia inutile che dispendioso qui. Ora stai obbligando new FileOutputStream()(tramite il sistema operativo) sia a eliminare il file così creato che a crearne uno nuovo.
Marchese di Lorne,

@EJP sì, era inutile, ora risolvo questo errore commesso durante la modifica. Ma createNewFIle () non è uno spreco, perché se CommonsMultipartFile è inferiore a 10240 byte, il file nel filesystem non viene creato. Quindi un nuovo file con un nome univoco (ho usato il nome di DiskFileItem) dovrebbe essere creato in FS.
Alex78191

@ Alex78191 Cosa intendi per salvare implicitamente su disco piccoli file (<10240 byte per impostazione predefinita). C'è comunque da aumentare il limite
Anand Tagore

@ AnandTagore Voglio dire che i byte inferiori a 10240 di MultipartFile non vengono salvati nel file system, quindi i file devono essere creati manualmente.
Alex78191

0

La risposta di Alex78191 ha funzionato per me.

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;
}

Per caricare file di dimensioni superiori a 10240 byte, modificare maxInMemorySize in multipartResolver a 1 MB.

<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>

maxInMemorySizenon ha nulla a che fare con la limitazione delle dimensioni di caricamento dei file. La dimensione del caricamento del file è impostata dalla maxUploadSizeproprietà.
Alex78191

Per sbarazzarsi del trucco con file inferiori a 10240 byte, è maxInMemorySizepossibile impostare prop 0.
Alex78191

@ Alex78191 L'ho cambiato e ha funzionato per me. Avevo usato il tuo codice per convertire il file. Quindi ho modificato le proprietà in applicationcontext.xml per eliminare i limiti di memoria. E funziona !!!
Anand Tagore

Durante la creazione di un file da un file multipart, dovrebbe essere mantenuto in memoria. Quindi per questo devo aumentare maxInMemorySize.
Anand Tagore

0

se non vuoi usare MultipartFile.transferTo (). Puoi scrivere file come questo

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

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

    FileOutputStream(file).use {
        it.write(multipartFile.bytes)
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.