如何设置InputStream内容长度
How to set InputStream content Length
我正在将文件上传到 Amazon S3 存储桶。正在上传文件,但我收到以下警告。
WARNING: No content length specified for stream data. Stream contents
will be buffered in memory and could result in out of memory errors.
所以我在我的代码中添加了以下行
metaData.setContentLength(IOUtils.toByteArray(input).length);
但后来我收到了以下消息。我什至不知道这是警告还是什么。
Data read has a different length than the expected: dataLength=0;
expectedLength=111992; includeSkipped=false; in.getClass()=class
sun.net.httpserver.FixedLengthInputStream; markedSupported=false;
marked=0; resetSinceLastMarked=false; markCount=0; resetCount=0
如何将 contentLength 设置为 InputSteam 的元数据?任何帮助将不胜感激。
当您使用 IOUtils.toByteArray
读取数据时,这会消耗 InputStream。当 AWS API 尝试读取它时,它的长度为零。
将内容读入一个字节数组并提供一个 InputStream 将该数组包装到 API:
byte[] bytes = IOUtils.toByteArray(input);
metaData.setContentLength(bytes.length);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, key, byteArrayInputStream, metadata);
client.putObject(putObjectRequest);
您应该考虑使用分段上传 API 以避免将整个 InputStream 加载到内存中。例如:
byte[] bytes = new byte[BUFFER_SIZE];
String uploadId = client.initiateMultipartUpload(new InitiateMultipartUploadRequest(bucket, key)).getUploadId();
int bytesRead = 0;
int partNumber = 1;
List<UploadPartResult> results = new ArrayList<>();
bytesRead = input.read(bytes);
while (bytesRead >= 0) {
UploadPartRequest part = new UploadPartRequest()
.withBucketName(bucket)
.withKey(key)
.withUploadId(uploadId)
.withPartNumber(partNumber)
.withInputStream(new ByteArrayInputStream(bytes, 0, bytesRead))
.withPartSize(bytesRead);
results.add(client.uploadPart(part));
bytesRead = input.read(bytes);
partNumber++;
}
CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest()
.withBucketName(bucket)
.withKey(key)
.withUploadId(uploadId)
.withPartETags(results);
client.completeMultipartUpload(completeRequest);
请注意,通过使用 ByteBuffer,您只需手动执行 AWS SDK 已自动为您执行的操作!它仍然将整个流缓冲到内存中,并且与从 SDK 产生警告的原始解决方案一样好。
如果您有另一种方法知道流的长度,例如,当您从文件创建流时,您只能解决内存问题:
void uploadFile(String bucketName, File file) {
try (final InputStream stream = new FileInputStream(file)) {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(file.length());
s3client.putObject(
new PutObjectRequest(bucketName, file.getName(), stream, metadata)
);
}
}
重磅消息! AWS SDK 2.0 内置支持上传文件:
s3client.putObject(
(builder) -> builder.bucket(myBucket).key(file.getName()),
RequestBody.fromFile(file)
);
还有 RequestBody
获取字符串或缓冲区的方法,这些方法可以自动有效地设置 Content-Length。只有当你有另一种 InputStream 时,你仍然需要自己提供长度——但是现在这种情况应该更罕见了,因为所有其他选项都可用。
我正在将文件上传到 Amazon S3 存储桶。正在上传文件,但我收到以下警告。
WARNING: No content length specified for stream data. Stream contents will be buffered in memory and could result in out of memory errors.
所以我在我的代码中添加了以下行
metaData.setContentLength(IOUtils.toByteArray(input).length);
但后来我收到了以下消息。我什至不知道这是警告还是什么。
Data read has a different length than the expected: dataLength=0; expectedLength=111992; includeSkipped=false; in.getClass()=class sun.net.httpserver.FixedLengthInputStream; markedSupported=false; marked=0; resetSinceLastMarked=false; markCount=0; resetCount=0
如何将 contentLength 设置为 InputSteam 的元数据?任何帮助将不胜感激。
当您使用 IOUtils.toByteArray
读取数据时,这会消耗 InputStream。当 AWS API 尝试读取它时,它的长度为零。
将内容读入一个字节数组并提供一个 InputStream 将该数组包装到 API:
byte[] bytes = IOUtils.toByteArray(input);
metaData.setContentLength(bytes.length);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, key, byteArrayInputStream, metadata);
client.putObject(putObjectRequest);
您应该考虑使用分段上传 API 以避免将整个 InputStream 加载到内存中。例如:
byte[] bytes = new byte[BUFFER_SIZE];
String uploadId = client.initiateMultipartUpload(new InitiateMultipartUploadRequest(bucket, key)).getUploadId();
int bytesRead = 0;
int partNumber = 1;
List<UploadPartResult> results = new ArrayList<>();
bytesRead = input.read(bytes);
while (bytesRead >= 0) {
UploadPartRequest part = new UploadPartRequest()
.withBucketName(bucket)
.withKey(key)
.withUploadId(uploadId)
.withPartNumber(partNumber)
.withInputStream(new ByteArrayInputStream(bytes, 0, bytesRead))
.withPartSize(bytesRead);
results.add(client.uploadPart(part));
bytesRead = input.read(bytes);
partNumber++;
}
CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest()
.withBucketName(bucket)
.withKey(key)
.withUploadId(uploadId)
.withPartETags(results);
client.completeMultipartUpload(completeRequest);
请注意,通过使用 ByteBuffer,您只需手动执行 AWS SDK 已自动为您执行的操作!它仍然将整个流缓冲到内存中,并且与从 SDK 产生警告的原始解决方案一样好。
如果您有另一种方法知道流的长度,例如,当您从文件创建流时,您只能解决内存问题:
void uploadFile(String bucketName, File file) {
try (final InputStream stream = new FileInputStream(file)) {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(file.length());
s3client.putObject(
new PutObjectRequest(bucketName, file.getName(), stream, metadata)
);
}
}
重磅消息! AWS SDK 2.0 内置支持上传文件:
s3client.putObject(
(builder) -> builder.bucket(myBucket).key(file.getName()),
RequestBody.fromFile(file)
);
还有 RequestBody
获取字符串或缓冲区的方法,这些方法可以自动有效地设置 Content-Length。只有当你有另一种 InputStream 时,你仍然需要自己提供长度——但是现在这种情况应该更罕见了,因为所有其他选项都可用。