2011-10-06 19 views

risposta

13

Mentre IOUtils.copy() e IOUtils.copyLarge() sono grandi, io preferirei la via vecchia scuola di loop attraverso l'InputStream fino InputStream restituisce -1. Perché? Ho usato IOUtils.copy() prima, ma c'era un caso d'uso specifico in cui, se ho iniziato a scaricare un file di grandi dimensioni da S3 e poi per qualche motivo se quel thread è stato interrotto, il download non si fermava e continuava fino al l'intero file è stato scaricato.

Naturalmente, questo non ha nulla a che fare con S3, solo la libreria IOUtils.

Quindi, preferisco questo:

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

Nota: Questo significa anche che non è necessario librerie aggiuntive

+0

Cosa devo fare se il file è gzip? –

+0

Genera eccezione indice OOB. –

+1

O semplicemente 'Files.copy (in, Paths.get ("/mio/percorso/file.jpg "))' come @Jonik ha risposto – Joan

4

classe L'AmazonS3Client ha il seguente metodo:

S3Object getObject(String bucketName, String key) 

Il S3Object tornato ha il metodo ...

java.io.InputStream getObjectContent() 

..che ottiene il contenuto oggetto come un flusso. Userei IOUtils da Apache Commons come questo:

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

+0

cosa devo fare se il file è compresso con gzip? –

17

Dal Java 7 (pubblicato a luglio 2011), c'è un modo migliore : Files.copy() utilità da java.util.nio.file.

Copia tutti i byte da un flusso di input a un file.

quindi è necessario an external library né posizionare il proprio byte array loops. Di seguito sono riportati due esempi, entrambi utilizzano il flusso di input da S3Object.getObjectContent().

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

1) Scrivi un nuovo file al percorso specificato:

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

2) scrivere in un file temporaneo nella posizione predefinita tmp del sistema:

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

(Senza specificare l'opzione per sostituire il file esistente, riceverai un FileAlreadyExistsException.)

Si noti inoltre che getObjectContent() Javadocs vi esorto a chiudere il flusso di input:

Se si recupera un S3Object, si dovrebbe chiudere questo flusso di input come più presto possibile, perché i contenuti degli oggetti non verranno inseriti nella memoria e streaming direttamente da Amazon S3. Inoltre, la mancata chiusura dello stream può causare il blocco del pool di richieste.

Così dovrebbe essere più sicuro di avvolgere tutto in try-catch-finally, e fare in.close(); nel blocco finally.

Quanto sopra presuppone che si usi l'SDK ufficiale da Amazon (aws-java-sdk-s3).

+0

Questo è un approccio molto migliore rispetto al vecchio modo di scorrere i byte. – Joan

+0

Preferisco fare 'Files.copy (in, Paths.get ("/mio/percorso/file.jpg "))'. Meglio ottenere il percorso senza passare attraverso il file – Joan

+0

@ Joan, punto giusto, aggiornato! – Jonik

1

Che dire di questo uno di linea utilizzando un TransferManager:

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