Как преобразовать составной файл в файл?

#java #spring #spring-mvc #file-upload #cloudinary

#java #spring #spring-mvc #загрузка файла #cloudinary

Вопрос:

Может кто-нибудь сказать мне, каков наилучший способ преобразования составного файла (org.springframework.web.multipart.MultipartFile) в файл (java.io.File)?

В моем веб-проекте spring mvc я получаю загруженный файл в виде составного файла.Я должен преобразовать его в файл (io), поэтому я могу вызвать эту службу хранения изображений (Cloudinary).Они принимают только тип (File).

Я выполнил так много поисковых запросов, но безуспешно.Если кто-нибудь знает хороший стандартный способ, пожалуйста, дайте мне знать? Спасибо

Комментарии:

1. Есть ли что-то, что мешает вам использовать этот метод MultipartFile.transferTo() ?

Ответ №1:

Вы можете получить содержимое a MultipartFile , используя getBytes метод, и вы можете записать в файл, используя 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());
    }
}
 

Вы также можете использовать метод transferTo:

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

Комментарии:

1. Я использовал функцию transferTo, но чувствую, что есть проблема. например, он сохраняет временный файл на диске для локального компьютера.

2. @Ronnie У меня такая же проблема. Вы нашли какой-нибудь обходной путь?

3. org.apache.commons.io.FileUtils. Удалить быстро (convFile.getParentFile()); , это должно удалить временный файл @Ronnie

4. createNewFIle() здесь это бессмысленно и расточительно. Теперь вы обязаны new FileOutputStream() (через ОС) удалить созданный таким образом файл и создать новый.

5. @Petros Tsialiamanis Есть ли ограничение на размер преобразования файлов в Java. Допустим, я использую 3 ГБ файла.

Ответ №2:

небольшое исправление в сообщении @Petroscialiamanis, new File( multipart.getOriginalFilename()) это создаст файл в расположении сервера, где когда-нибудь вы столкнетесь с проблемами с разрешением на запись для пользователя, не всегда возможно предоставить разрешение на запись каждому пользователю, который выполняет действие. System.getProperty("java.io.tmpdir") создаст временный каталог, в котором ваш файл будет создан должным образом. Таким образом, вы создаете временную папку, в которой создается файл, позже вы можете удалить файл или временную папку.

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

поместите этот метод в общую утилиту ur и используйте его, например, для. Utility.multipartToFile(...)

Комментарии:

1. это должно быть правильным ответом (особенно для использования каталога tmp, потому что это решит некоторые проблемы, такие как отказ в разрешении в Linux)

2. @HoussemBadri да, учитывая проблемы с разрешениями и т. Д., Это необходимо.

3. Пользователь Linux здесь, только это решение сработало для меня. 2021. спасибо

Ответ №3:

Хотя принятый ответ правильный, но если вы просто пытаетесь загрузить свое изображение в cloudinary, есть лучший способ:

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

Где MultipartFile — это ваш org.springframework.web.multipart.MultipartFile.

Комментарии:

1. По какой-то причине cloudinary возвращается RuntimeException: Missing required parameter - file , когда я указываю upload() метод byte[] в качестве параметра файла. Так раздражает.

Ответ №4:

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

Комментарии:

1. предоставление этого исключения java.io.FileNotFoundException: multipdf.pdf (отказано в разрешении)

Ответ №5:

MultipartFile.transferTo(File) — это хорошо, но не забудьте все-таки очистить временный файл.

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

Ознакомьтесь с комментарием Раззлеро о File.deleteOnExit(), выполняемом при выходе из JVM (что может быть крайне редко), подробности приведены ниже.

Комментарии:

1. deleteOnExit() он будет срабатывать только при завершении работы JVM, поэтому он не будет срабатывать во время исключений. Из-за этого вам нужно быть осторожным при использовании deleteOnExit() в долго работающих приложениях, таких как серверные приложения. Для серверных приложений JVM редко завершается. Поэтому вам нужно быть осторожным deleteOnExit() , чтобы не вызвать утечку памяти. JVM необходимо отслеживать все файлы, которые необходимо удалить при выходе, которые не очищаются, поскольку JVM не завершается.

2. @Razzlero спасибо, что указали, что он удаляет файлы только при выходе из JVM. Однако это не утечка памяти, все работает так, как задумано.

Ответ №6:

Вы также можете использовать библиотеку ввода-вывода Apache Commons и класс FileUtils. Если вы используете maven, вы можете загрузить его, используя указанную выше зависимость.

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

Исходный код для составного файла сохранить на диск.

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

Комментарии:

1. FileUtils.touch() здесь это бессмысленно и расточительно. Теперь вы обязаны new FileOutputStream() (через ОС) удалить созданный таким образом файл и создать новый.

2. Спасибо за ваш комментарий. Я проверил источник метода FileUtils. writeByteArrayToFile. Я думаю, что этот метод не воссоздает файл, если он существует (версия 2.4). Объект MultipartFile включает байты загруженного файла, которые мы хотим сохранить где-нибудь в файловой системе. Моя цель — сохранить эти байты в предпочтительном месте. Единственная причина, по которой я сохраняю FileUtils. сенсорный метод заключается в том, чтобы дать понять, что это новый файл. Файловые файлы. writeByteArrayToFile создает файл (и полный путь) в случае, если он не существует, поэтому FileUtils . касание не требуется.

Ответ №7:

Вы можете получить доступ к tempfile весной путем приведения, если класс интерфейса 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;
}
 

Чтобы избавиться от трюка с файлами размером менее 10240 байт maxInMemorySize , свойству можно присвоить значение 0 в @Configuration @EnableWebMvc классе. После этого все загруженные файлы будут сохранены на диске.

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

Комментарии:

1. createNewFIle() здесь это бессмысленно и расточительно. Теперь вы обязаны new FileOutputStream() (через ОС) удалить созданный таким образом файл и создать новый.

2. @EJP да, это было бессмысленно, теперь я исправляю эту ошибку, допущенную при редактировании. Но createNewFile() не является расточительным, потому что, если размер CommonsMultipartFile меньше 10240 байт, файл в файловой системе не создается. Таким образом, в FS должен быть создан новый файл с любым уникальным именем (я использовал имя DiskFileItem).

3. @Alex78191 Что вы подразумеваете под неявным сохранением на диске небольших файлов (<10240 байт по умолчанию). Есть ли способ увеличить лимит

4. @AnandTagore Я имею в виду, что многокомпонентный файл размером менее 10 240 байт не сохраняется в файловой системе, поэтому файлы должны создаваться вручную.

Ответ №8:

Ответ в одну строку с использованием Apache Commons.

FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);

Ответ №9:

Ответ Alex78191 сработал для меня.

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

Для загрузки файлов размером более 10 240 байт, пожалуйста, измените maxInMemorySize в MultipartResolver на 1 МБ.

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

Комментарии:

1. maxInMemorySize не имеет ничего общего с ограничением размера загружаемого файла. Размер загружаемого файла задается maxUploadSize свойством.

2. Чтобы избавиться от трюка с файлами размером менее 10240 байт maxInMemorySize , prop можно установить 0 равным .

3. @Alex78191 Я изменил это, и это сработало для меня. Я использовал ваш код для преобразования файла. Итак, я изменил свойства в applicationcontext.xml чтобы избавиться от ограничений памяти. И это работает!!!

4. При создании файла из составного файла он должен храниться в памяти. Итак, для этого я должен увеличить maxInMemorySize.

Ответ №10:

если вы не хотите использовать MultipartFile.transferTo() . Вы можете записать файл следующим образом

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

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

    FileOutputStream(file).use {
        it.write(multipartFile.bytes)
    }
 

Ответ №11:

MultipartFile может получить входной поток.

MultipartFile.getInputStream()