У меня есть много файлов на S3, которые мне нужно заархивировать, а затем предоставить zip через S3.В настоящее время я архивирую их из потока в локальный файл, а затем снова загружаю файл.Это занимает много места на диске, так как каждый файл имеет около 3-10 МБ, и мне нужно сжать до 100 000 файлов.Таким образом, почтовый индекс может иметь более 1 ТБ.Поэтому я хотел бы найти решение именно по этой линии:
Создайте zip-файл на S3 из файлов на S3, используя Lambda Node
Здесь швы, zip создается напрямуюна S3, не занимая место на локальном диске.Но я просто недостаточно умен, чтобы перенести вышеуказанное решение на Java.Я также нахожу противоречивую информацию о java aws sdk, говоря, что они планировали изменить поведение потока в 2017 году.
Не уверен, поможет ли это, но вот что я делал до сих пор (Upload
это моя локальная модель, которая содержит информацию S3).Я просто удалил логи и прочее для лучшей читаемости.Я думаю, что я не занимаю место для загрузки, "обвязывая" InputStream непосредственно в почтовый индекс.Но, как я уже сказал, я также хотел бы избежать локального файла zip и создать его непосредственно на S3.Однако для этого, вероятно, потребуется создать ZipOutputStream с S3 в качестве цели вместо FileOutputStream.Не уверен, как это можно сделать.
public File zipUploadsToNewTemp(List<Upload> uploads) {
List<String> names = new ArrayList<>();
byte[] buffer = new byte[1024];
File tempZipFile;
try {
tempZipFile = File.createTempFile(UUID.randomUUID().toString(), ".zip");
} catch (Exception e) {
throw new ApiException(e, BaseErrorCode.FILE_ERROR, "Could not create Zip file");
}
try (
FileOutputStream fileOutputStream = new FileOutputStream(tempZipFile);
ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream)) {
for (Upload upload : uploads) {
InputStream inputStream = getStreamFromS3(upload);
ZipEntry zipEntry = new ZipEntry(upload.getFileName());
zipOutputStream.putNextEntry(zipEntry);
writeStreamToZip(buffer, zipOutputStream, inputStream);
inputStream.close();
}
zipOutputStream.closeEntry();
zipOutputStream.close();
return tempZipFile;
} catch (IOException e) {
logError(type, e);
if (tempZipFile.exists()) {
FileUtils.delete(tempZipFile);
}
throw new ApiException(e, BaseErrorCode.IO_ERROR,
"Error zipping files: " + e.getMessage());
}
}
// I am not even sure, but I think this takes up memory and not disk space
private InputStream getStreamFromS3(Upload upload) {
try {
String filename = upload.getId() + "." + upload.getFileType();
InputStream inputStream = s3FileService
.getObject(upload.getBucketName(), filename, upload.getPath());
return inputStream;
} catch (ApiException e) {
throw e;
} catch (Exception e) {
logError(type, e);
throw new ApiException(e, BaseErrorCode.UNKOWN_ERROR,
"Unkown Error communicating with S3 for file: " + upload.getFileName());
}
}
private void writeStreamToZip(byte[] buffer, ZipOutputStream zipOutputStream,
InputStream inputStream) {
try {
int len;
while ((len = inputStream.read(buffer)) > 0) {
zipOutputStream.write(buffer, 0, len);
}
} catch (IOException e) {
throw new ApiException(e, BaseErrorCode.IO_ERROR, "Could not write stream to zip");
}
}
И, наконец, загрузить исходный код.Inputstream создается из временного Zip-файла.
public PutObjectResult upload(InputStream inputStream, String bucketName, String filename, String folder) {
String uploadKey = StringUtils.isEmpty(folder) ? "" : (folder + "/");
uploadKey += filename;
ObjectMetadata metaData = new ObjectMetadata();
byte[] bytes;
try {
bytes = IOUtils.toByteArray(inputStream);
} catch (IOException e) {
throw new ApiException(e, BaseErrorCode.IO_ERROR, e.getMessage());
}
metaData.setContentLength(bytes.length);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketPrefix + bucketName, uploadKey, byteArrayInputStream, metaData);
putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead);
try {
return getS3Client().putObject(putObjectRequest);
} catch (SdkClientException se) {
throw s3Exception(se);
} finally {
IOUtils.closeQuietly(inputStream);
}
}
Только что нашел вопрос, аналогичный тому, что мне нужно, также без ответа:
Загрузка ZipOutputStream в S3 без сохранения ZIP-файла (большой) временно на диск с помощью AWS S3 Java