web-dev-qa-db-ja.com

InputStreamコンテンツの長さを設定する方法

Amazon S3バケットにファイルをアップロードしています。ファイルはアップロードされていますが、次の警告が表示されます。

警告:ストリームデータのコンテンツの長さは指定されていません。ストリームのコンテンツはメモリにバッファリングされ、メモリ不足エラーが発生する可能性があります。

そこで、次の行をコードに追加しました

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

しかし、その後、私は次のメッセージを受け取りました。それが警告なのか、何なのかさえわかりません。

読み取られたデータの長さが予想とは異なります:dataLength = 0; expectedLength = 111992; includeSkipped = false; in.getClass()= class Sun.net.httpserver.FixedLengthInputStream; markSupported = false;マーク= 0; resetSinceLastMarked = false; markCount = 0; resetCount = 0

ContentLengthをInputSteamのmetaDataに設定するにはどうすればよいですか?どんな助けも大歓迎です。

20
Shaonline

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

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

速報! AWS SDK 2.0には、ファイルのアップロードのサポートが組み込まれています:

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

Content-Lengthを自動的かつ効率的に設定する文字列またはバッファを取得するRequestBodyメソッドもあります。別の種類のInputStreamを使用する場合にのみ、長さを自分で指定する必要がありますが、他のすべてのオプションを使用できるようになったため、このケースはよりまれになります。

1