Як перетворити багаточастинний файл у файл?


89

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

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

Я зробив так багато пошуків, але не вдалося. Якщо хтось знає хороший стандартний спосіб, будь ласка, повідомте мене? Thnx


5
Чи є щось, що заважає вам використовувати метод MultipartFile.transferTo()?
fajarkoe

Відповіді:


192

Ви можете отримати вміст 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, але, на мою думку, є проблема. типу Він зберігає тимчасовий файл для керування локальною машиною.
Морез

@Ronnie У мене така ж проблема. Ви знайшли якийсь обхідний шлях?
Напівкровний принц

1
org.apache.commons.io.FileUtils.deleteQuietly (convFile.getParentFile ()); , це повинно видалити тимчасовий файл @Ronnie
kavinder

5
createNewFIle()тут і безглуздо, і марнотратно. Тепер ви зобов’язуєте new FileOutputStream()(через ОС) як видалити створений таким чином файл, так і створити новий.
Маркіз Лорнський

@Petros Tsialiamanis Чи має обмеження розміру конвертації файлів у Java? Скажімо, я використовую 3 ГБ файлу.
Рохіт

17

невелике виправлення в дописі @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;
}

помістіть цей метод у загальну утиліту і використовуйте його, наприклад, наприклад. Utility.multipartToFile(...)


16

Хоча прийнята відповідь є правильною, але якщо ви просто намагаєтесь завантажити своє зображення в хмарний, є кращий спосіб:

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()(через ОС) як видалити створений таким чином файл, так і створити новий.
Маркіз Лорнський

Дякуємо за ваш коментар. Я перевірив джерело методу FileUtils.writeByteArrayToFile. Я думаю, що цей метод не відтворює файл у разі його існування (версія 2.4). Об'єкт multipartFile включає байти завантаженого файлу, який ми хочемо зберегти десь у файловій системі. Моя мета - зберегти ці байти у бажаному місці. Єдина причина, по якій я зберігаю метод FileUtils.touch, - це чітко пояснити, що це новий файл. FileUtils.writeByteArrayToFile створює файл (і повний шлях), якщо він не існує, тому FileUtils.touch не потрібен.
George Siggouroglou

7

MultipartFile.transferTo (Файл) приємний, але не забудьте все-таки очистити тимчасовий файл.

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

Ознайомтесь із коментарем Razzlero щодо File.deleteOnExit (), виконаного при виході з JVM (що може бути надзвичайно рідко) нижче.


2
deleteOnExit(), він буде спрацьовувати лише тоді, коли JVM закінчується, тому він не запускатиметься під час винятків. Через це вам потрібно бути обережним при використанні deleteOnExit()на довго працюючих додатках, таких як серверні програми. Для серверних програм JVM рідко виходить. Тому потрібно бути обережним, щоб не deleteOnExit()викликати витоки пам’яті. JVM повинен відстежувати всі файли, які йому потрібно видалити при виході, які не очищені, оскільки JVM не завершує роботу.
Razzlero

@Razzlero дякує, що вказав, що він видаляє файли лише після виходу з JVM. Однак це не витік пам'яті, він працює за задумом.
андрей

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

даючи цей виняток java.io.FileNotFoundException: multipdf.pdf (дозвіл відмовлено)
Navnath Adsul

1

Ви можете отримати доступ до тимчасового файлу навесні лиття , якщо клас інтерфейсу 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у @Configuration @EnableWebMvcкласі можна встановити значення 0 . Після цього всі завантажені файли будуть зберігатися на диску.

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

2
createNewFIle()тут і безглуздо, і марнотратно. Тепер ви зобов’язуєте new FileOutputStream()(через ОС) як видалити створений таким чином файл, так і створити новий.
Маркіз Лорнський

@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 на 1MB.

<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

Щоб позбутися фокусу з файлами менше 10240 байт maxInMemorySize, можна встановити prop 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)
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.