Как записать объект 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 );