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

92

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

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

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

Амила Иддамалгода
источник
5
Есть ли что-то, что мешает вам использовать этот метод MultipartFile.transferTo()?
fajarkoe

Ответы:

195

Вы можете получить содержимое 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);
}
Петрос Циалиаманис
источник
7
Я использовал функцию transferTo, но чувствую, что есть проблема. Например, он хранит временный файл для локального компьютера.
Morez
@Ronnie, у меня такая же проблема. Вы нашли обходной путь?
Принц-полукровка,
1
org.apache.commons.io.FileUtils.deleteQuietly (convFile.getParentFile ()); , это должно удалить временный файл @Ronnie
kavinder
5
createNewFIle()здесь бессмысленно и расточительно. Теперь вы обязуетесь new FileOutputStream()(через ОС) как удалить созданный таким образом файл, так и создать новый.
user207421 06
@Petros Tsialiamanis Есть ли ограничение на размер конвертации файлов в Java. Скажем, я использую 3 ГБ файла.
Rohit
19

небольшое исправление в сообщении @PetrosTsialiamanis, 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(...)

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

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

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

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

Гейзенберг
источник
8

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

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

Источник для сохранения 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()здесь бессмысленно и расточительно. Теперь вы обязуетесь new FileOutputStream()(через ОС) как удалить созданный таким образом файл, так и создать новый.
user207421 06
Спасибо за ваш комментарий. Я проверил источник метода FileUtils.writeByteArrayToFile. Я думаю, что этот метод не воссоздает файл, если он существует (версия 2.4). Объект multipartFile включает байты загруженного файла, которые мы хотим сохранить где-нибудь в файловой системе. Моя цель - сохранить эти байты в предпочтительном месте. Единственная причина, по которой я сохраняю метод FileUtils.touch, - это дать понять, что это новый файл. FileUtils.writeByteArrayToFile создает файл (и полный путь) в случае, если он не существует, поэтому FileUtils.touch не требуется.
Джордж Сиггуроглу
7

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 (что может быть крайне редко), подробности ниже.

андрей
источник
2
deleteOnExit(), он сработает только при завершении работы JVM, поэтому не будет запускаться во время исключений. Из-за этого вам нужно быть осторожным при использовании deleteOnExit()в долго работающих приложениях, таких как серверные приложения. Для серверных приложений JVM редко завершает работу. Поэтому нужно быть осторожным, чтобы не deleteOnExit()вызвать утечки памяти. JVM необходимо отслеживать все файлы, которые необходимо удалить при выходе, которые не очищаются, поскольку JVM не завершает работу.
Razzlero
@Razzlero благодарит за указание, что он удаляет файлы только после выхода из JVM. Однако это не утечка памяти, это работает как задумано.
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
источник
предоставление этого исключения java.io.FileNotFoundException: multipdf.pdf (Permission denied)
Navnath Adsul
2

Вы можете получить доступ к временному файлу весной литья , если класс интерфейса 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;
    }
Alex78191
источник
2
createNewFIle()здесь бессмысленно и расточительно. Теперь вы обязуетесь new FileOutputStream()(через ОС) как удалить созданный таким образом файл, так и создать новый.
user207421 06
@EJP да, это было бессмысленно, теперь исправлю ошибку, допущенную при редактировании. Но createNewFIle () не является расточительным, потому что, если CommonsMultipartFile меньше 10240 байт, файл в файловой системе не создается. Таким образом, новый файл с любым уникальным именем (я использовал имя DiskFileItem) должен быть создан в FS.
Alex78191
@ Alex78191 Что вы имеете в виду под неявным сохранением на диск небольших файлов (по умолчанию <10240 байт). Есть ли способ увеличить лимит
Ананд Тагор
@AnandTagore Я имею в виду, что размер MultipartFile меньше 10240 байт не сохраняется в файловой системе, поэтому файлы следует создавать вручную.
Alex78191
0

Ответ 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;
}

Для загрузки файлов размером более 10240 байт измените 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>
Ананд Тагор
источник
maxInMemorySizeне имеет ничего общего с ограничением на размер загружаемого файла. Размер загружаемого файла задается в maxUploadSizeсобственности.
Alex78191
1
Чтобы избавиться от трюка с файлами размером менее 10240 байт, для параметра maxInMemorySizeprop можно установить значение 0.
Alex78191
@ Alex78191 Я изменил это, и у меня это сработало. Я использовал ваш код для преобразования файла. Поэтому я изменил свойства в applicationcontext.xml, чтобы избавиться от ограничений памяти. И это работает !!!
Ананд Тагор
Создавая файл из составного файла, он должен храниться в памяти. Поэтому для этого мне нужно увеличить maxInMemorySize.
Ананд Тагор
0

если вы не хотите использовать 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)
    }
Артем Ботнев
источник