Làm thế nào để chuyển đổi một tệp nhiều phần thành Tệp?


89

Bất kỳ ai có thể cho tôi biết cách tốt nhất để chuyển đổi một tệp đa phần (org.springframework.web.multipart.MultipartFile) thành tệp (java.io.File) là gì không?

Trong dự án web mvc mùa xuân của tôi, tôi nhận được tệp tải lên dưới dạng tệp Multipart, tôi phải chuyển đổi nó thành Tệp (io), ở đó tôi có thể gọi dịch vụ lưu trữ hình ảnh này ( Cloudinary ). Họ chỉ lấy loại (Tệp).

Tôi đã thực hiện rất nhiều tìm kiếm nhưng không thành công. Nếu ai biết một cách tiêu chuẩn tốt xin vui lòng cho tôi biết? Thnx


5
Có điều gì ngăn cản bạn sử dụng phương pháp này MultipartFile.transferTo()không?
fajarkoe

Câu trả lời:


192

Bạn có thể lấy nội dung của a MultipartFilebằng getBytesphương thức này và bạn có thể ghi vào tệp bằng cách sử dụng 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());
    }
}

Bạn cũng có thể sử dụng phương thức transferTo :

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

7
Tôi đã sử dụng Hàm transferTo nhưng tôi cảm thấy có vấn đề. như Nó giữ tệp tạm thời để lái cho máy cục bộ.
Morez

@Ronnie Tôi đang gặp vấn đề tương tự. Bạn đã tìm thấy bất kỳ giải pháp nào chưa?
Half Blood Prince

1
org.apache.commons.io.FileUtils.deleteQuietly (concFile.getParentFile ()); , Điều này sẽ xóa các tập tin tạm thời @Ronnie
kavinder

5
createNewFIle()vừa vô nghĩa vừa lãng phí ở đây. Bây giờ bạn bắt buộc new FileOutputStream()(thông qua HĐH) xóa cả tệp đã tạo tạo một tệp mới.
Marquis of Lorne

@Petros Tsialiamanis Nó có giới hạn kích thước chuyển đổi tệp nào trong Java không. Giả sử tôi đang sử dụng 3GB tệp.
Rohit

17

sửa lỗi nhỏ trên bài đăng @PetrosTsialiamanis, new File( multipart.getOriginalFilename())điều này sẽ tạo tệp ở vị trí máy chủ mà đôi khi bạn sẽ gặp phải các vấn đề về quyền ghi cho người dùng, không phải lúc nào cũng có thể cấp quyền ghi cho mọi người dùng thực hiện hành động. System.getProperty("java.io.tmpdir")sẽ tạo thư mục tạm thời nơi tệp của bạn sẽ được tạo đúng cách. Bằng cách này, bạn đang tạo thư mục tạm thời, nơi tệp được tạo, sau này bạn có thể xóa tệp hoặc thư mục tạm thời.

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

đặt phương thức này trong tiện ích chung của bạn và sử dụng nó như ví dụ. Utility.multipartToFile(...)


16

Mặc dù câu trả lời được chấp nhận là đúng nhưng nếu bạn chỉ đang cố gắng tải hình ảnh của mình lên đám mây, có một cách tốt hơn:

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

Trong đó MultiartFile là org.springframework.web.multipart.MultipartFile của bạn .


8

Bạn cũng có thể sử dụng thư viện Apache Commons IOlớp FileUtils . Trong trường hợp bạn đang sử dụng maven, bạn có thể tải nó bằng cách sử dụng phụ thuộc ở trên.

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

Nguồn để lưu MultipartFile vào đĩa.

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()vừa vô nghĩa vừa lãng phí ở đây. Bây giờ bạn bắt buộc new FileOutputStream()(thông qua HĐH) phải xóa cả tệp đã tạo tạo một tệp mới.
Marquis of Lorne,

Cảm ơn bình luận của bạn. Tôi đã kiểm tra nguồn của phương thức FileUtils.writeByteArrayToFile. Tôi nghĩ rằng phương pháp này không phải là tạo lại tệp trong trường hợp nó tồn tại (phiên bản 2.4). Đối tượng MultiartFile bao gồm các byte của tệp đã tải lên mà chúng ta muốn lưu trữ ở đâu đó trong hệ thống tệp. Mục đích của tôi là lưu trữ các byte này vào một vị trí ưu tiên. Lý do duy nhất tôi giữ phương thức FileUtils.touch là để làm rõ rằng đây là một tệp mới. FileUtils.writeByteArrayToFile tạo tệp (và đường dẫn đầy đủ) trong trường hợp tệp không tồn tại, do đó FileUtils.touch không cần thiết.
George Siggouroglou

7

MultipartFile.transferTo (File) rất hay, nhưng đừng quên dọn dẹp tệp tạm thời.

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

Kiểm tra bình luận của Razzlero về File.deleteOnExit () được thực thi khi thoát JVM (có thể rất hiếm) chi tiết bên dưới.


2
deleteOnExit(), nó sẽ chỉ kích hoạt khi JVM kết thúc, vì vậy nó sẽ không kích hoạt trong các trường hợp ngoại lệ. Vì điều này, bạn cần phải cẩn thận khi sử dụng deleteOnExit()trên các ứng dụng chạy lâu như ứng dụng máy chủ. Đối với các ứng dụng máy chủ, JVM sẽ hiếm khi thoát. Vì vậy, bạn cần phải cẩn thận deleteOnExit()gây ra rò rỉ bộ nhớ. JVM cần theo dõi tất cả các tệp cần xóa khi thoát mà không bị xóa vì JVM không kết thúc.
Razzlero

@Razzlero cảm ơn bạn đã chỉ ra rằng nó chỉ xóa tệp khi thoát JVM. Tuy nhiên, nó không phải là rò rỉ bộ nhớ, nó hoạt động như thiết kế.
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;
    }

đưa ra ngoại lệ này java.io.FileNotFoundException: Multidf.pdf (Quyền bị từ chối)
Navnath Adsul

1

Bạn có thể truy cập tempfile trong Spring bằng cách truyền nếu lớp giao diện MultipartFileCommonsMultipartFile.

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

Để thoát khỏi thủ thuật với các tệp nhỏ hơn 10240 byte, thuộc maxInMemorySizetính có thể được đặt thành 0 trong @Configuration @EnableWebMvclớp. Sau đó, tất cả các tệp đã tải lên sẽ được lưu trữ trên đĩa.

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

2
createNewFIle()vừa vô nghĩa vừa lãng phí ở đây. Bây giờ bạn bắt buộc new FileOutputStream()(thông qua HĐH) xóa cả tệp đã tạo tạo một tệp mới.
Marquis of Lorne,

@EJP vâng, thật vô nghĩa, bây giờ tôi sửa lỗi này trong khi chỉnh sửa. Nhưng createNewFIle () không lãng phí, vì nếu CommonsMultipartFile nhỏ hơn 10240 byte, tệp trong hệ thống tệp sẽ không được tạo. Vì vậy, một tệp mới với bất kỳ tên duy nhất nào (tôi đã sử dụng tên DiskFileItem) sẽ được tạo trong FS.
Alex78191

@ Alex78191 Ý bạn là gì khi hoàn toàn lưu trên đĩa các tệp nhỏ (<10240 byte theo mặc định). Có cách nào để tăng giới hạn không
Anand Tagore.

@AnandTagore Ý tôi là ít hơn 10240 byte của MultipartFile không được lưu trong hệ thống tệp, vì vậy Tệp phải được tạo theo cách thủ công.
Alex78191 29/09/16

0

Câu trả lời của Alex78191 đã phù hợp với tôi.

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

Để tải lên các tệp có kích thước lớn hơn 10240 byte, vui lòng thay đổi maxInMemorySize trong MultiartResolver thành 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>

maxInMemorySizekhông liên quan gì đến giới hạn về kích thước tệp tải lên. Kích thước tải lên tệp do thuộc maxUploadSizetính đặt.
Alex78191 23/02/17

Để thoát khỏi thủ thuật với các tệp nhỏ hơn 10240 byte, bạn maxInMemorySizecó thể đặt thành 0.
Alex78191 23/02/17

@ Alex78191 Tôi đã thay đổi điều này và nó phù hợp với tôi. Tôi đã sử dụng mã của bạn để chuyển đổi tệp. Vì vậy, tôi đã thay đổi các thuộc tính trong applicationcontext.xml để loại bỏ các giới hạn bộ nhớ. Và nó hoạt động !!!
Anand Tagore

Trong khi tạo tệp từ tệp nhiều phần, nó phải được lưu trong bộ nhớ. Vì vậy, tôi phải tăng maxInMemorySize.
Anand Tagore

0

nếu bạn không muốn sử dụng MultipartFile.transferTo (). Bạn có thể viết tệp như thế này

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

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

    FileOutputStream(file).use {
        it.write(multipartFile.bytes)
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.