- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我需要从 S3 下载照片(不在同一目录中),将它们压缩并使用 AWS S3 Java SDK 再次上传到 S3。此 zip 文件大小可以 GB 为单位。目前我使用的是 AWS Lambda,它的临时存储限制为 500 MB。所以我不想将 ZIP 文件保存在磁盘上,而是想将 ZIP 文件(使用从 S3 下载的照片动态创建)直接流式传输到 S3。我需要使用 AWS S3 Java SDK。
最佳答案
基本思想是使用流操作。这样您就不会等到 ZIP 在文件系统上生成,而是尽快开始上传,因为 ZIP 算法会生成任何数据。显然,一些数据会缓存在内存中,仍然不需要等待整个 ZIP 生成到磁盘上。我们还将在两个线程中使用流组合和 PipedInputStream
/PipedOutputStream
:一个读取数据,另一个压缩内容。
这是 aws-java-sdk 的版本:
final AmazonS3 client = AmazonS3ClientBuilder.defaultClient();
final PipedOutputStream pipedOutputStream = new PipedOutputStream();
final PipedInputStream pipedInputStream = new PipedInputStream(pipedOutputStream);
final Thread s3In = new Thread(() -> {
try (final ZipOutputStream zipOutputStream = new ZipOutputStream(pipedOutputStream)) {
S3Objects
// It's just a convenient way to list all the objects. Replace with you own logic.
.inBucket(client, "bucket")
.forEach((S3ObjectSummary objectSummary) -> {
try {
if (objectSummary.getKey().endsWith(".png")) {
System.out.println("Processing " + objectSummary.getKey());
final ZipEntry entry = new ZipEntry(
UUID.randomUUID().toString() + ".png" // I'm too lazy to extract file name from the
// objectSummary
);
zipOutputStream.putNextEntry(entry);
IOUtils.copy(
client.getObject(
objectSummary.getBucketName(),
objectSummary.getKey()
).getObjectContent(),
zipOutputStream
);
zipOutputStream.closeEntry();
}
} catch (final Exception all) {
all.printStackTrace();
}
});
} catch (final Exception all) {
all.printStackTrace();
}
});
final Thread s3Out = new Thread(() -> {
try {
client.putObject(
"another-bucket",
"previews.zip",
pipedInputStream,
new ObjectMetadata()
);
pipedInputStream.close();
} catch (final Exception all) {
all.printStackTrace();
}
});
s3In.start();
s3Out.start();
s3In.join();
s3Out.join();
但是,请注意它会打印警告:
WARNING: No content length specified for stream data. Stream contents will be buffered in memory and could result in out of memory errors.
那是因为S3需要在上传之前提前知道数据的大小。不可能提前知道生成的 ZIP 的大小。你可以试试你的运气 multipart uploads ,但代码会更棘手。虽然,想法是相似的:一个线程应该读取数据并发送 ZIP 流中的内容,而另一个线程应该读取压缩条目并将它们作为多部分上传。上传所有条目(部分)后,应完成多部分。
这是 aws-java-sdk-2.x 的示例:
final S3Client client = S3Client.create();
final PipedOutputStream pipedOutputStream = new PipedOutputStream();
final PipedInputStream pipedInputStream = new PipedInputStream(pipedOutputStream);
final Thread s3In = new Thread(() -> {
try (final ZipOutputStream zipOutputStream = new ZipOutputStream(pipedOutputStream)) {
client.listObjectsV2Paginator(
ListObjectsV2Request
.builder()
.bucket("bucket")
.build()
)
.contents()
.forEach((S3Object object) -> {
try {
if (object.key().endsWith(".png")) {
System.out.println("Processing " + object.key());
final ZipEntry entry = new ZipEntry(
UUID.randomUUID().toString() + ".png" // I'm too lazy to extract file name from the object
);
zipOutputStream.putNextEntry(entry);
client.getObject(
GetObjectRequest
.builder()
.bucket("bucket")
.key(object.key())
.build(),
ResponseTransformer.toOutputStream(zipOutputStream)
);
zipOutputStream.closeEntry();
}
} catch (final Exception all) {
all.printStackTrace();
}
});
} catch (final Exception all) {
all.printStackTrace();
}
});
final Thread s3Out = new Thread(() -> {
try {
client.putObject(
PutObjectRequest
.builder()
.bucket("another-bucket")
.key("previews.zip")
.build(),
RequestBody.fromBytes(
IOUtils.toByteArray(pipedInputStream)
)
);
} catch (final Exception all) {
all.printStackTrace();
}
});
s3In.start();
s3Out.start();
s3In.join();
s3Out.join();
它有同样的问题:ZIP 需要在上传前在内存中准备好。
如果你有兴趣,我准备了一个demo project , 这样您就可以玩代码了。
关于java - 使用 AWS S3 Java 将 ZipOutputStream 上传到 S3 而无需将 zip 文件(大)临时保存到磁盘,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55204181/
我可以压缩文件,但内容错误......例如 - a.txt 中的内容: !"#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abc
我希望能够通过网络读取多个数据流并将文件写入网络以组合所有这些多个文件。 由于文件可能非常大,我不想做任何本地IO文件操作,而是对数据流进行操作。从网络读取流,将流以 zip 格式写入网络。 我正在尝
我有两个例子: 示例 1: try (ByteArrayOutputStream baous = new ByteArrayOutputStream(); FileOutputStre
我正在使用 ZipOutputStream创建 ZIP 文件。它工作正常,但 Javadoc 非常稀疏,所以我对 ZipOutputStream 的特性有疑问: 支持的最大文件大小是否有限制?对于 Z
我试图通过 ZipOutputStream 输出数据,但生成的文件未压缩。这是在 Windows 7 下。这是一个示例: import java.io.*; import java.nio.file.
我使用 ZipOutputStream 创建 zip 文件。我把一个文件放在zip中(文件和zip都在同一个目录),但是文件是用完整路径存储的(C:\TEMP\file.xml),如何用相对路径或没有
我需要压缩来自一个流的数据并将压缩数据放入另一个流。下面是操作文件的代码(MyOutputStream 是一个用于调试目的的简单 FileOutputStream 包装器)。此代码工作正常。
我有点困惑。我知道空 zip 是不合法的。但是这个示例片段呢: ZipOutputStream zos = null; try { zos = new ZipOutputStream(new
我想使用 java.util.ZipOutputStream 类压缩文本文件。我在互联网上找到了两个示例来解释如何做到这一点。这使我想到了如下所示的两种可能的实现。虽然这两种方法都会生成“健康的 zi
我想创建 zip 文件。文件将包含导出的 Preferences 和 Serialized 对象。但是当我尝试替换 zip 存档中的对象时,保存的首选项消失了。如何解决这个问题? import jav
这个问题不太可能对任何 future 的访客有帮助;它只与一个较小的地理区域、一个特定的时间点或一个非常狭窄的情况相关,通常不适用于全世界的互联网受众。如需帮助使此问题更广泛适用,visit the
我必须上传一个zip文件到ftp服务器,这里的zip文件也是动态构建的。 import java.io.File; import java.io.FileInputStream; import jav
我尝试用 DeflaterOutputStream 压缩一个字符串并用 base64 转换输出以将结果保存在另一个字符串中 public static String compress(String s
我正在使用 Java7 编写代码,并使用 try-with-resources 功能。当我创建 ZipOutputStream 的实例时。通过这样做,我不再需要在finally block 中关闭流。
我正在尝试使用 MockitoJUnitRunner 编写 JUnit。我将文件 ID 传递给我的函数,该函数从云下载文件并返回 zip 文件作为下载。这是我的代码 public void getLo
我的 bean 类中有以下代码块 - HttpServletResponse response = (HttpServletResponse) getFacesContext().getExterna
这真的是一个由两部分组成的问题。 前言:我用WinRAR压缩文件。它为您提供了仅压缩某些文件的选项。我可以按文件扩展名进行过滤,例如,JPEG 文件不会被压缩,而其他文件会被压缩。 这可以用一般的 Z
ZipOutputStream 仅压缩文件夹中的文件。我也想压缩子文件夹。我怎样才能做到这一点? 最佳答案 您必须递归地探索您的目录才能添加 zip 中的所有文件。 如果你愿意,可以看看这个小 hel
我有一个要返回给浏览器的 ZipOutputStream。我想要的体验是用户点击一个 anchor 标签,然后为我有的ZipOutputStream 显示一个文件下载提示。 如何将 ZipOutput
我正在使用此处描述的技术创建一个 zip 文件: http://info.michael-simons.eu/2008/01/21/using-rubyzip-to-create-zip-files-
我是一名优秀的程序员,十分优秀!