Wie konvertiere ich eine mehrteilige Datei in Datei?

87

Kann mir jemand sagen, wie eine mehrteilige Datei (org.springframework.web.multipart.MultipartFile) am besten in eine Datei (java.io.File) konvertiert werden kann?

In meinem mvc-Webprojekt im Frühjahr erhalte ich eine hochgeladene Datei als mehrteilige Datei. Ich muss sie in eine Datei (io) konvertieren, daher kann ich diesen Bildspeicherdienst ( Cloudinary ) aufrufen. Sie nehmen nur den Typ (Datei).

Ich habe so viele Suchvorgänge durchgeführt, die jedoch fehlgeschlagen sind. Wenn jemand einen guten Standardweg kennt, lassen Sie es mich bitte wissen. Danke

Amila Iddamalgoda
quelle
5
Gibt es etwas, das Sie daran hindert, die Methode anzuwenden MultipartFile.transferTo()?
Fajarkoe

Antworten:

192

Sie können den Inhalt von a MultipartFilemithilfe der getBytesMethode abrufen und in die Datei schreiben, indem Sie 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());
    }
}

Sie können auch die transferTo-Methode verwenden :

public void multipartFileToFile(
    MultipartFile multipart, 
    Path dir
) throws IOException {
    Path filepath = Paths.get(dir.toString(), multipart.getOriginalFilename());
    multipart.transferTo(filepath);
}
Petros Tsialiamanis
quelle
7
Ich habe transferTo Function verwendet, aber ich habe das Gefühl, dass es ein Problem gibt. wie Es hält temporäre Datei, um für lokalen Computer zu fahren.
Morez
@ Ronnie Ich habe das gleiche Problem. Haben Sie eine Problemumgehung gefunden?
Halbblutprinz
1
org.apache.commons.io.FileUtils.deleteQuietly (convFile.getParentFile ()); , dies sollte die temporäre Datei @Ronnie
Kavinder
5
createNewFIle()ist hier sowohl sinnlos als auch verschwenderisch. Sie verpflichten sich jetzt new FileOutputStream()(über das OS) , um sowohl die Datei zu löschen , so erstellt und eine neue erstellen.
Marquis von Lorne
@Petros Tsialiamanis Gibt es in Java eine Größenbeschränkung für die Dateikonvertierung? Angenommen, ich verwende 3 GB Datei.
Rohit
16

Die akzeptierte Antwort ist zwar richtig, aber wenn Sie nur versuchen, Ihr Bild in Cloudinary hochzuladen, gibt es einen besseren Weg:

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

Wobei multipartFile Ihr org.springframework.web.multipart.MultipartFile ist .

Heisenberg
quelle
16

Bei einer kleinen Korrektur des Beitrags @PetrosTsialiamanis new File( multipart.getOriginalFilename())wird eine Datei am Serverstandort erstellt, bei der manchmal Probleme mit der Schreibberechtigung für den Benutzer auftreten. Es ist nicht immer möglich, jedem Benutzer, der eine Aktion ausführt, eine Schreibberechtigung zu erteilen. System.getProperty("java.io.tmpdir")erstellt ein temporäres Verzeichnis, in dem Ihre Datei ordnungsgemäß erstellt wird. Auf diese Weise erstellen Sie einen temporären Ordner, in dem eine Datei erstellt wird. Später können Sie eine Datei oder einen temporären Ordner löschen.

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

Setzen Sie diese Methode in Ihr allgemeines Dienstprogramm ein und verwenden Sie sie wie z. Utility.multipartToFile(...)

Swadeshi
quelle
8

Sie können auch die Apache Commons IO- Bibliothek und die FileUtils-Klasse verwenden . Wenn Sie maven verwenden, können Sie es mit der oben genannten Abhängigkeit laden.

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

Die Quelle für die MultipartFile-Speicherung auf der Festplatte.

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
quelle
FileUtils.touch()ist hier sowohl sinnlos als auch verschwenderisch. Sie verpflichten sich jetzt new FileOutputStream()(über das OS) , um sowohl die Datei zu löschen , so erstellt und eine neue erstellen.
Marquis von Lorne
Danke für deinen Kommentar. Ich habe die Quelle der Methode FileUtils.writeByteArrayToFile überprüft. Ich denke, dass diese Methode die Datei nicht neu erstellt, falls sie existiert (Version 2.4). Das multipartFile-Objekt enthält die Bytes der hochgeladenen Datei, die irgendwo im Dateisystem gespeichert werden sollen. Mein Zweck ist es, diese Bytes an einem bevorzugten Ort zu speichern. Der einzige Grund, warum ich die FileUtils.touch-Methode behalte, besteht darin, klar zu machen, dass es sich um eine neue Datei handelt. Die Datei FileUtils.writeByteArrayToFile erstellt die Datei (und den vollständigen Pfad), falls sie nicht vorhanden ist, sodass die Datei FileUtils.touch nicht erforderlich ist.
George Siggouroglou
7

MultipartFile.transferTo (File) ist nett, aber vergessen Sie nicht, die temporäre Datei zu bereinigen.

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

Lesen Sie den Kommentar von Razzlero zu File.deleteOnExit (), der beim Beenden der JVM ausgeführt wird (was äußerst selten sein kann).

andrej
quelle
2
deleteOnExit()wird nur ausgelöst, wenn die JVM beendet wird, sodass sie während Ausnahmen nicht ausgelöst wird. Aus diesem Grund müssen Sie deleteOnExit()bei lang laufenden Anwendungen wie Serveranwendungen vorsichtig sein . Bei Serveranwendungen wird die JVM selten beendet. Sie müssen also vorsichtig sein deleteOnExit(), um Speicherlecks zu verursachen. Die JVM muss alle Dateien verfolgen, die beim Beenden gelöscht werden müssen und die nicht gelöscht werden, da die JVM nicht beendet wird.
Razzlero
@Razzlero bedankt sich für den Hinweis, dass Dateien nur beim Beenden von JVM gelöscht werden. Es ist jedoch kein Speicherverlust, es funktioniert wie geplant.
andrej
3
  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
quelle
Geben dieser Ausnahme java.io.FileNotFoundException: multipdf.pdf (Berechtigung verweigert)
Navnath Adsul
1

Sie können im Frühjahr zugreifen tempfile durch Gießen , wenn die Klasse der Schnittstelle MultipartFileist 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;
}

Um den Trick mit Dateien mit weniger als 10240 Byte loszuwerden, maxInMemorySizekann die Eigenschaft in der @Configuration @EnableWebMvcKlasse auf 0 gesetzt werden . Danach werden alle hochgeladenen Dateien auf der Festplatte gespeichert.

@Bean(name = "multipartResolver")
    public CommonsMultipartResolver createMultipartResolver() {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setDefaultEncoding("utf-8");
        resolver.setMaxInMemorySize(0);
        return resolver;
    }
Alex78191
quelle
2
createNewFIle()ist hier sowohl sinnlos als auch verschwenderisch. Sie verpflichten sich jetzt new FileOutputStream()(über das OS) , um sowohl die Datei zu löschen , so erstellt und eine neue erstellen.
Marquis von Lorne
@EJP ja, es war sinnlos, jetzt behebe ich diesen Fehler, der beim Bearbeiten gemacht wurde. CreateNewFIle () ist jedoch keine Verschwendung, da die Datei im Dateisystem nicht erstellt wird, wenn CommonsMultipartFile weniger als 10240 Byte beträgt. Daher sollte im FS eine neue Datei mit einem eindeutigen Namen (ich habe den Namen DiskFileItem verwendet) erstellt werden.
Alex78191
@ Alex78191 Was Sie unter implizitem Speichern kleiner Dateien auf der Festplatte verstehen (standardmäßig <10240 Byte). Gibt es sowieso, um das Limit zu erhöhen
Anand Tagore
@AnandTagore Ich meine, dass MultipartFiles weniger als 10240 Bytes nicht im Dateisystem gespeichert werden, daher sollten Dateien manuell erstellt werden.
Alex78191
0

Die Antwort von Alex78191 hat bei mir funktioniert.

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

Zum Hochladen von Dateien mit einer Größe von mehr als 10240 Byte ändern Sie bitte die maxInMemorySize in multipartResolver auf 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>
Anand Tagore
quelle
maxInMemorySizehat nichts mit der Beschränkung der Größe des Datei-Uploads zu tun. Die Größe des Datei-Uploads wird von der maxUploadSizeEigenschaft festgelegt.
Alex78191
Um den Trick mit Dateien mit weniger als 10240 Bytes loszuwerden, maxInMemorySizekann prop auf gesetzt werden 0.
Alex78191
@ Alex78191 Ich habe das geändert und es hat bei mir funktioniert. Ich hatte Ihren Code zum Konvertieren der Datei verwendet. Also habe ich die Eigenschaften in der applicationcontext.xml geändert, um die Speicherbeschränkungen zu beseitigen. Und es funktioniert !!!
Anand Tagore
Beim Erstellen einer Datei aus einer mehrteiligen Datei sollte diese im Speicher bleiben. Dafür muss ich die maxInMemorySize erhöhen.
Anand Tagore
0

Wenn Sie MultipartFile.transferTo () nicht verwenden möchten. Sie können eine Datei wie diese schreiben

    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
quelle