如何将多部分文件转换为文件?


89

谁能告诉我将多部分文件(org.springframework.web.multipart.MultipartFile)转换为File(java.io.File)的最佳方法是什么?

在我的春季MVC Web项目中,我正在以Multipart文件的形式上传文件。我必须将其转换为File(io),因此我可以将此图像存储服务称为Cloudinary。它们仅采用(File)类型。

我进行了很多次搜索,但都失败了。如果有人知道一种标准的方法,请告诉我?n


5
有什么可以阻止您使用该方法的MultipartFile.transferTo()吗?
fajarkoe 2014年

Answers:


192

您可以MultipartFile使用getBytes方法获取a的内容,并可以使用写入文件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 Function,但是我觉得有问题。就像它保留临时文件以驱动本地计算机。
Morez 2015年

@罗尼我有同样的问题。您找到任何解决方法了吗?
Half Blood Prince

1
org.apache.commons.io.FileUtils.deleteQuietly(convFile.getParentFile()); ,这应删除临时文件@Ronnie
kavinder

5
createNewFIle()在这里既毫无意义又浪费。现在,您必须new FileOutputStream()(通过OS)删除这样创建的文件创建一个新文件。
罗恩侯爵,

@Petros Tsialiamanis Java是否具有任何文件转换大小限制。假设我正在使用3GB的文件。
罗希特

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

尽管公认的答案是正确的,但是如果您只是尝试将图像上传到cloudinary,则有更好的方法:

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

其中multipartFile是您的org.springframework.web.multipart.MultipartFile


8

您还可以使用Apache Commons IO库和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()(通过OS)删除这样创建的文件创建一个新文件。
罗恩侯爵,

感谢您的评论。我检查了方法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();

在下面查看有关Razzlero在JVM退出时执行的File.deleteOnExit()的评论(这可能非常罕见)的详细信息。


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

给出此异常java.io.FileNotFoundException:multipdf.pdf(权限被拒绝)
Navnath Adsul,

1

如果接口的类MultipartFile是,则可以通过强制转换在Spring中访问tempfile 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()(通过OS)删除这样创建的文件创建一个新文件。
洛恩侯爵

@EJP是的,这毫无意义,现在我修复了编辑时犯的这个错误。但是createNewFIle()并不浪费,因为如果CommonsMultipartFile小于10240字节,则不会创建文件系统中的文件。因此,应在FS中创建一个具有任何唯一名称的新文件(我使用DiskFileItem的名称)。
Alex78191 '16

@ Alex78191您的意思是隐式保存在磁盘上的小文件(默认情况下<10240字节)。无论如何,有没有增加限额
Anand Tagore

@AnandTagore我的意思是小于10240字节的MultipartFile不会保存在文件系统中,因此应手动创建文件。
Alex78191 '16

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字节的文件,请将multipartResolver中的maxInMemorySize更改为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 '17

要摆脱文件少于10240字节的情况,maxInMemorySize可以将prop设置为0
Alex78191 '17

@ 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)
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.