2011-10-06 122 views

回答

13

雖然IOUtils.copy()IOUtils.copyLarge()是偉大的,我寧願通過InputStream的循環,直到的InputStream返回-1的老同學的方式。爲什麼?我用IOUtils.copy()之前,但有在那裏,如果我開始下載從S3較大的文件,然後由於某種原因,如果線程被中斷的具體使用情況,下載不會停止,它會繼續下去,直到整個文件被下載。

當然,這無關與S3,只是IOUtils庫。

所以,我更喜歡這樣的:

InputStream in = s3Object.getObjectContent(); 
byte[] buf = new byte[1024]; 
OutputStream out = new FileOutputStream(file); 
while((count = in.read(buf)) != -1) 
{ 
    if(Thread.interrupted()) 
    { 
     throw new InterruptedException(); 
    } 
    out.write(buf, 0, count); 
} 
out.close(); 
in.close(); 

注:這也意味着你不需要額外的庫

+0

如果文件被壓縮,該怎麼辦? –

+0

引發索引OOB異常。 –

+1

或者簡單地執行'Files.copy(in,Paths.get(「/ my/path/file.jpg」))'@Jonik回答 – Joan

4

的AmazonS3Client類有以下方法:

S3Object getObject(String bucketName, String key) 

返回S3Object有法...

java.io.InputStream getObjectContent() 

..這獲取對象內容流。我會用IOUtils從Apache的百科全書是這樣的:

IOUtils.copy(s3Object.getObjectContent(), new FileOutputStream(new File(filepath)));

+0

我應該做的,如果該文件是gzip壓縮? –

17

由於的Java 7(2011年7月發佈回),還有一個更好的方法:Files.copy()來自java.util.nio.file的實用程序。

副本從輸入流中的文件中的所有字節。

所以你需要既不an external library也不滾動自己byte array loops。以下兩個示例使用來自S3Object.getObjectContent()的輸入流。

InputStream in = s3Client.getObject("bucketName", "key").getObjectContent(); 

1)寫入到一個新的文件,在指定的路徑:

Files.copy(in, Paths.get("/my/path/file.jpg")); 

2)寫入到一個臨時文件在系統的默認tmp目錄位置:

File tmp = File.createTempFile("s3test", ""); 
Files.copy(in, tmp.toPath(), StandardCopyOption.REPLACE_EXISTING); 

(如果沒有指定選項,以取代現有的文件,你會得到一個FileAlreadyExistsException

另外請注意,getObjectContent() Javadocs敦促你關閉輸入流

如果您檢索S3Object,您應該很快就會關閉此輸入流作爲 越好,因爲對象的內容不會在緩衝 內存和直接來自Amazon S3的流。此外,故障關閉 這個流可以導致請求池被阻塞。

因此,應該最安全地包裝try-catch-finally中的所有內容,並在finally塊中執行in.close();

上面假設您使用亞馬遜的官方SDK(aws-java-sdk-s3)。

+0

這比通過字節循環的舊方法要好得多。 – Joan

+0

我寧願做'Files.copy(in,Paths.get(「/ my/path/file.jpg」))''。更好的路徑而不通過文件 – Joan

+0

@Joan,公平點,更新! – Jonik

1

怎麼樣使用TransferManager這一個班輪:

TransferManagerBuilder.defaultTransferManager 
    .download("bucket-name", "key", new File("."))