Çok parçalı bir dosyayı dosyaya nasıl dönüştürebilirim?


92

Biri bana çok parçalı bir dosyayı (org.springframework.web.multipart.MultipartFile) Dosyaya (java.io.File) dönüştürmenin en iyi yolunun ne olduğunu söyleyebilir mi?

İlkbahar mvc web projemde Multipart dosyası olarak yüklenen dosyayı alıyorum, bunu bir Dosya (io) haline getirmem gerekiyor, bu nedenle bu görüntü depolama servisini ( Cloudinary ) arayabilirim .

Çok fazla arama yaptım ama başarısız oldum, iyi bir standart yol bilen varsa lütfen bana bildirin. Thnx


5
Yöntemi kullanmanızı engelleyen bir şey var mı MultipartFile.transferTo()?
fajarkoe

Yanıtlar:


195

Yöntemi MultipartFilekullanarak a'nın içeriğini alabilir getBytesve aşağıdakileri kullanarak dosyaya yazabilirsiniz 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 yöntemini de kullanabilirsiniz :

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

7
TransferTo İşlevini kullandım ama bir sorun olduğunu hissediyorum. gibi Yerel makine için sürmek üzere temp dosyasını tutar.
Morez

@Ronnie Ben de aynı sorunu yaşıyorum. Herhangi bir geçici çözüm buldunuz mu?
Melez Prens

1
org.apache.commons.io.FileUtils.deleteQuietly (convFile.getParentFile ()); , bu geçici dosyayı silmeli @Ronnie
kavinder

5
createNewFIle()burada hem anlamsız hem de savurgan. Artık sendikadaki vardır new FileOutputStream()böylece oluşturulan dosyayı silmek hem (OS yoluyla) ve yeni bir tane oluşturun.
user207421

@Petros Tsialiamanis Java'da herhangi bir Dosya dönüştürme boyutu sınırı var mı? Diyelim ki 3GB dosya kullanıyorum.
Rohit

19

@PetrosTsialiamanis gönderisinde küçük bir düzeltme, new File( multipart.getOriginalFilename())bu, bazen kullanıcı için yazma izni sorunlarıyla karşılaşacağınız sunucu konumunda dosya oluşturacaktır, eylemi gerçekleştiren her kullanıcıya yazma izni vermek her zaman mümkün değildir. System.getProperty("java.io.tmpdir")dosyanızın düzgün bir şekilde oluşturulacağı geçici dizin oluşturacaktır. Bu şekilde, dosyanın oluşturulduğu geçici klasör oluşturursunuz, daha sonra dosyayı veya geçici klasörü silebilirsiniz.

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

bu yöntemi ortak yardımcı programınıza koyun ve örneğin kullanın. Utility.multipartToFile(...)


bu doğru cevap olmalıdır (özellikle tmp dizinini kullanmak için, çünkü
linux'ta

17

Kabul edilen cevap doğru olsa da, sadece görselinizi cloudinary'e yüklemeye çalışıyorsanız, daha iyi bir yol var:

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

MultipartFile, org.springframework.web.multipart.MultipartFile dosyanızdır .


8

Apache Commons IO kitaplığını ve FileUtils sınıfını da kullanabilirsiniz . Maven kullanıyorsanız, yukarıdaki bağımlılığı kullanarak yükleyebilirsiniz.

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

MultipartFile için kaynak diske kaydetme.

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()burada hem anlamsız hem de savurgan. Artık sendikadaki vardır new FileOutputStream()böylece oluşturulan dosyayı silmek hem (OS yoluyla) ve yeni bir tane oluşturun.
user207421

Yorumun için teşekkür ederim. FileUtils.writeByteArrayToFile yönteminin kaynağını kontrol ettim. Bu yöntemin, var olması durumunda dosyayı yeniden oluşturmadığını düşünüyorum (sürüm 2.4). MultipartFile nesnesi, dosya sisteminde bir yerde saklamak istediğimiz karşıya yüklenen dosyanın baytlarını içerir. Amacım bu baytları tercih edilen bir yerde saklamak. FileUtils.touch yöntemini korumamın tek nedeni, bunun yeni bir dosya olduğunu açıklığa kavuşturmaktır. FileUtils.writeByteArrayToFile, mevcut olmaması durumunda dosyayı (ve tam yolu) oluşturur, bu nedenle FileUtils.touch gerekli değildir.
George Siggouroglou

7

MultipartFile.transferTo (Dosya) güzeldir, ancak sonuçta geçici dosyayı temizlemeyi unutmayın.

// 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'nun JVM çıkışında yürütülen File.deleteOnExit () hakkındaki yorumuna (çok nadir olabilir) aşağıdaki ayrıntılara göz atın.


2
deleteOnExit(), yalnızca JVM sona erdiğinde tetiklenir, bu nedenle istisnalar sırasında tetiklenmez. Bu nedenle, deleteOnExit()sunucu uygulamaları gibi uzun süre çalışan uygulamaları kullanırken dikkatli olmanız gerekir . Sunucu uygulamaları için JVM nadiren çıkacaktır. Bu nedenle, deleteOnExit()bellek sızıntılarına neden olma konusunda dikkatli olmanız gerekir . JVM, çıkışta silmesi gereken ve JVM sona ermediği için silinmeyen tüm dosyaları takip etmelidir.
Razzlero

@Razzlero, yalnızca JVM çıkışında dosyaları sildiğini belirttiğiniz için teşekkürler. Ancak bellek sızıntısı değil, tasarlandığı gibi çalışıyor.
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;
    }

bu istisnayı veren java.io.FileNotFoundException: multipdf.pdf (İzin reddedildi)
Navnath Adsul

2

Sen arayüzün sınıf ise döküm tarafından İlkbaharda tempfile erişebilir MultipartFileolduğunu 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 bayttan daha küçük dosyalarla hile yapmaktan kurtulmak için maxInMemorySizeözelliği @Configuration @EnableWebMvcsınıfta 0 olarak ayarlanabilir . Bundan sonra, yüklenen tüm dosyalar diskte saklanacaktır.

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

2
createNewFIle()burada hem anlamsız hem de savurgan. Artık sendikadaki vardır new FileOutputStream()böylece oluşturulan dosyayı silmek hem (OS yoluyla) ve yeni bir tane oluşturun.
user207421

@EJP evet, anlamsızdı, şimdi düzenleme sırasında yapılan bu hatayı düzelttim. Ancak createNewFIle () israf değildir, çünkü CommonsMultipartFile 10240 bayttan azsa, dosya sistemindeki dosya oluşturulmaz. Bu nedenle, FS'de herhangi bir benzersiz ada sahip (DiskFileItem adını kullandım) yeni bir dosya oluşturulmalıdır.
Alex78191

@ Alex78191 Küçük dosyalara (varsayılan olarak <10240 bayt) örtük olarak kaydetmekten kastınız. Sınırı artırmak için yine de var mı
Anand Tagore

@AnandTagore MultipartFile'ın 10240 bayttan daha azının dosya sistemine kaydedilmediği için Dosyalar manuel olarak oluşturulmalıdır.
Alex78191

0

Alex78191'in cevabı benim için çalıştı.

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 bayttan daha büyük boyutlu dosyaları yüklemek için lütfen multipartResolver'daki maxInMemorySize değerini 1MB olarak değiştirin.

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

maxInMemorySizedosya yükleme boyutundaki sınırlamayla ilgisi yoktur. Dosya yükleme boyutu maxUploadSizemülk tarafından belirlenir .
Alex78191

1
10240 bayttan daha küçük dosyalarla hünerden kurtulmak için maxInMemorySizeprop olarak ayarlanabilir 0.
Alex78191

@ Alex78191 Bunu değiştirdim ve benim için çalıştı. Dosyayı dönüştürmek için kodunuzu kullandım. Bu yüzden bellek sınırlamalarından kurtulmak için applicationcontext.xml'deki özellikleri değiştirdim. Ve çalışıyor !!!
Anand Tagore

Çok parçalı dosyadan dosya oluştururken hafızada tutulmalıdır. Yani bunun için maxInMemorySize'ı arttırmam gerekiyor.
Anand Tagore

0

MultipartFile.transferTo () kullanmak istemiyorsanız. Böyle bir dosya yazabilirsin

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

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

    FileOutputStream(file).use {
        it.write(multipartFile.bytes)
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.