2011-10-06 15 views

Respuesta

13

Mientras IOUtils.copy() y IOUtils.copyLarge() son grandes, yo prefiero la vieja escuela de bucle a través del flujo de entrada hasta que el InputStream devuelve -1. ¿Por qué? Utilicé IOUtils.copy() antes, pero había un caso de uso específico donde si comenzaba a descargar un archivo grande de S3 y luego, por algún motivo, si ese hilo se interrumpía, la descarga no se detenía y seguía y seguía hasta que todo el archivo fue descargado

Por supuesto, esto no tiene nada que ver con S3, solo con la biblioteca IOUtils.

Por lo tanto, prefiero esto:

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: Esto también significa que no es necesario bibliotecas adicionales

+0

¿Qué debo hacer si el archivo tiene gzip? –

+0

Lanza la excepción OOB de índice. –

+1

O simplemente haga 'Files.copy (en, Paths.get ("/my/path/file.jpg "))' como @Jonik respondió – Joan

4

clase El AmazonS3Client tiene el siguiente método:

S3Object getObject(String bucketName, String key) 

El S3Object devuelto tiene el método ...

java.io.InputStream getObjectContent() 

..which obtiene el contenido objeto como una corriente. Que haría uso de Apache Commons IOUtils así:

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

+0

lo que debería hacer si se gzipped el archivo? –

17

Desde Java 7 (publicado en julio de 2011), hay una manera mejor : Files.copy() utilidad desde java.util.nio.file.

Copia todos los bytes de un flujo de entrada a un archivo.

por lo que necesita ni an external library ni rodar su propia byte array loops. Dos ejemplos a continuación, que usan el flujo de entrada desde S3Object.getObjectContent().

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

1) escribir en un archivo nuevo en ruta especificada:

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

2) escribir en un archivo temporal en la localización tmp por defecto del sistema:

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

(Sin especificar la opción para reemplazar el archivo existente, obtendrá un FileAlreadyExistsException).

También tenga en cuenta que getObjectContent() Javadocs que instan a cerrar el flujo de entrada:

Si recupera un S3Object, debería cerrar este flujo de entrada como pronto como sea posible, ya que el contenido del objeto no se almacenan en memoria y transmitir directamente desde Amazon S3. Además, si no se cierra esta secuencia, puede provocar que se bloquee el grupo de solicitudes.

Por lo tanto, debería ser más seguro envolver todo en try-catch-finally, y hacer in.close(); en el bloque finally.

Lo anterior supone que utiliza el SDK oficial de Amazon (aws-java-sdk-s3).

+0

Esta es una aproximación mucho mejor que la antigua forma de recorrer bytes. – Joan

+0

Preferiría hacer 'Files.copy (en, Paths.get ("/my/path/file.jpg "))'. Es mejor obtener la ruta sin pasar por el archivo – Joan

+0

@Joan, punto justo, ¡actualizado! – Jonik

1

¿Qué hay de éste revestimiento utilizando un TransferManager:

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