Как установить содержимое InputStream Длина

Я загружаю файлы в ведро Amazon S3. Файлы загружаются, но я получаю следующее предупреждение.

ПРЕДУПРЕЖДЕНИЕ: для данных потока не указана длина содержимого. Содержимое потока будет буферизован в памяти и может привести к ошибкам памяти.

Итак, я добавил следующую строку в свой код

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

но затем я получил следующее сообщение. Я даже не знаю, это предупреждение или что.

Чтение данных имеет разную длину, чем ожидалось: dataLength = 0; expectedLength = 111992; includeSkipped = ложь; in.getClass() = класс sun.net.httpserver.FixedLengthInputStream; markedSupported = ложь; отмеченные = 0; resetSinceLastMarked = ложь; markCount = 0; resetCount = 0

Как я могу установить contentLength для метаданных InputSteam? Любая помощь будет принята с благодарностью.

Ответ 1

Когда вы читаете данные с помощью 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);

Ответ 2

Обратите внимание, что с помощью 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)
        );
    }
}

Ответ 3

Последние новости! AWS SDK 2.0 имеет встроенную поддержку для загрузки файлов:

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

Есть также методы RequestBody для получения строк или буферов, которые автоматически и эффективно устанавливают Content-Length. Только когда у вас есть другой тип InputStream, вам все равно нужно указывать длину самостоятельно - однако этот случай должен быть более редким сейчас со всеми другими доступными опциями.