如何设置InputStream内容长度

时间:2016-03-24 13:49:41

标签: amazon-web-services amazon-s3 metadata inputstream

我正在将文件上传到Amazon S3存储桶。文件正在上传,但我得到以下警告。

  

警告:没有为流数据指定内容长度。流内容   将被缓冲在内存中,并可能导致内存不足错误。

所以我在代码中添加了以下行

metaData.setContentLength(IOUtils.toByteArray(input).length);

然后我收到以下消息。我甚至都不知道这是警告还是什么。

  

数据读取的长度与预期的不同:dataLength = 0;   expectedLength = 111992; includeSkipped = FALSE; in.getClass()=类   sun.net.httpserver.FixedLengthInputStream; markedSupported = FALSE;   标记= 0; resetSinceLastMarked = FALSE; markCount = 0; resetCount = 0

如何将contentLength设置为InputSteam的metaData?任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:23)

当您使用IOUtils.toByteArray读取数据时,会消耗InputStream。当AWS API尝试读取它时,它的长度为零。

将内容读入字节数组并提供将该数组包装到API的InputStream:

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);

答案 1 :(得分:1)

请注意,通过使用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)
        );
    }
}

答案 2 :(得分:0)

最新消息! AWS SDK 2.0具有对上传文件的内置支持:

        s3client.putObject(
                (builder) -> builder.bucket(myBucket).key(file.getName()),
                RequestBody.fromFile(file)
        );

还有RequestBody个用于获取字符串或缓冲区的方法,这些方法可自动有效地设置Content-Length。仅当您拥有另一种InputStream时,您仍然需要自己提供长度-但是,在使用所有其他选项的情况下,这种情况现在应该很少见了。