Как записать объект S3 в файл?

Какой самый быстрый способ записи объекта S3 (от которого у меня есть ключ) в файл? Я использую Java.

6 ответов

Решение

В то время как IOUtils.copy() а также IOUtils.copyLarge() отлично, я бы предпочел старый способ циклически проходить по входному потоку, пока входной поток не вернет -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();

Примечание: это также означает, что вам не нужны дополнительные библиотеки

Начиная с Java 7 (опубликованной в июле 2011 года), есть лучший способ: Files.copy() утилита из java.util.nio.file,

Копирует все байты из входного потока в файл.

Таким образом, вам не нужны ни внешняя библиотека, ни циклы собственных байтовых массивов. Два примера ниже, оба из которых используют входной поток из S3Object.getObjectContent(),

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

1) Записать в новый файл по указанному пути:

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

2) Записать во временный файл в системном местоположении по умолчанию:

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

(Без указания опции для замены существующего файла, вы получите FileAlreadyExistsException.)

Также обратите внимание, что getObjectContent() Javadocs призывает вас закрыть поток ввода:

Если вы извлекаете объект S3Object, вам следует как можно скорее закрыть этот входной поток, поскольку содержимое объекта не буферизуется в памяти и не передается непосредственно из Amazon S3. Кроме того, отказ закрыть этот поток может привести к блокировке пула запросов.

Так что должно быть безопаснее обернуть все в try-catch-finally и сделать in.close(); в блоке, наконец.

Выше предполагается, что вы используете официальный SDK от Amazon (aws-java-sdk-s3).

Класс AmazonS3Client имеет следующий метод:

S3Object getObject(String bucketName, String key)

Возвращенный S3Object имеет метод...

java.io.InputStream getObjectContent()

... который получает содержимое объекта в виде потока. Я бы использовал IOUtils от Apache Commons следующим образом:

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

Как насчет этого одного вкладыша с помощью TransferManager:

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

В AWS SDK для Java v2, выпущенном в 2017 году, вы можете просто указать Path для записи в файл.

s3.getObject(GetObjectRequest.builder().bucket(bucket).key(key).build(),
        ResponseTransformer.toFile(Paths.get("multiPartKey")));

https://docs.aws.amazon.com/sdk-for-java/v2/developer-guide/examples-s3-objects.html#download-object

Если вам нужен File, вы можете использовать toFile метод.

Path path = Paths.get("file.txt");
s3.getObject(GetObjectRequest.builder().bucket(bucket).key(key).build(),
        path);
File file = path.toFile();
                  byte[] content = IOUtils.toByteArray(myS3Object.getObjectContent());

            // path where to save the file
            File myFile = new File("/home/ayoub/Android/release.apk");

            //save content to file
            FileUtils.writeByteArrayToFile(apkFile, content);

            // OPTIONAL if you'd like to return a resource
            Resource resource = new ByteArrayResource( content );
Другие вопросы по тегам