Загрузка Android AWS s3 SDK вызывает исключение «Socket is closed» или завершается досрочно - PullRequest
3 голосов
/ 22 декабря 2011

Я пытаюсь загрузить объект из S3, используя AWS Android SDK 1.0.4 или 1.0.3.

Это мой код:

AmazonS3Client client = getConnection(userCredentials);
S3Object obj = client.getObject(workspaceName, objectName);
ObjectMetadata meta = obj.getObjectMetadata();
long size = meta.getContentLength();
logger.info("S3 object length: "+size);
InputStream is = new BufferedInputStream(obj.getObjectContent());
byte[] fragmentBytes = IOUtils.toByteArray(is);
logger.info("Read bytes: "+ fragmentBytes.length);

Это иногда, редко, работает.В большинстве случаев выдается сообщение «java.net.SocketException: Socket is closed» или не сообщается об ошибке, но читается только часть объекта.

Обратите внимание, что BufferedInputStream не требуетсядля IOUtils.toByteArray(...) и не имеет значения, есть ли он там или нет.

Похоже, что проблема не возникает при пошаговом выполнении кода в отладчике.

Это происходит намое устройство Android 2.3.3 и устройство 3.2.Это происходит через Wi-Fi и 3G.

Есть идеи?

ps> Размер объектов около 250 тыс.

Ответы [ 4 ]

4 голосов
/ 01 февраля 2013

Проблема в том, что клиент собирает мусор.Чтобы исправить это, вам нужно сохранить явную ссылку на S3Client.

Поток ошибки выглядит следующим образом:

  1. Программа получает клиента S3
  2. Программа получает объект S3 от клиента.
  3. Программа получает inputStream от s3Object, который получает его через клиента.
  4. Сборка мусора запускается, и поскольку нет ссылки на клиента, она получает сборщик мусора, случайным образом закрывая ваш inputStream.

IMO, это очень плохая ошибка Amazon.Почему поток ввода объекта S3 не имеет обратной ссылки на клиента, для меня загадка.

Вот тема на форумах AWS: https://forums.aws.amazon.com/thread.jspa?threadID=83326

2 голосов
/ 28 ноября 2012

Вы, вероятно, уже решили эту проблему, но я не смог найти правильный ответ и в итоге выяснил его сам, поэтому вот решение:

Документация по методам getObjectContent очень четко описывает закрытие InputStream:

S3ObjectInputStream com.amazonaws.services.s3.model.S3Object.getObjectContent ()

Получает входной поток, содержащий содержимое этого объекта.Вызывающие абоненты должны закрыть этот входной поток как можно скорее, потому что содержимое объекта не буферизуется в памяти и не передается напрямую из Amazon S3.

Вы делаете ту же ошибку, что и я, используя InputStream (S3Object), как если бы замыкание было прозрачным.

Я предполагаю, что вам нужно получить изображение из S3, чтобы оно былоиспользуется на Android, поэтому здесь идет пример метода, который возвращает растровое изображение.Это действительно относится к любому виду ввода.

private Bitmap getFromStore(String fileName) {
    AmazonS3Client client = new AmazonS3Client(new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY));

    S3Object o = client.getObject(BUCKET, fileName);
    InputStream is = o.getObjectContent();

    Bitmap image = null;

    try {   
        // Use the inputStream and close it after.
        image = BitmapFactory.decodeStream(is);
    } finally {
        try {
            is.close();
        } catch (IOException e) {
            Log.w(TAG, "Error trying to close image stream. ", e);
        }
    }

    return image;
}

На всякий случай не забудьте выполнить это в другом потоке, отличном от пользовательского интерфейса.

Удачи,

1 голос
/ 22 декабря 2011

Ну, кажется, вы не одиноки.В принятом в ответе сообщается о вашей проблеме.

Как записать объект S3 в файл?

Я бы попробовал зациклить содержимое, как ответ на вопрос выше.Буферизованные это хорошо, но ....

Вы также можете попробовать не использовать IOUtil, ведь в Java есть другие опции.

0 голосов
/ 06 июня 2016

нет необходимости повторной инициализации s3.

В вашем onCreate сделайте вызов для инициализации s3Object и s3Client.

Тогда используйте звонок в вашем asynctask. Таким образом, ваш s3Client сохранит те же данные и никогда не закроет сокетное соединение с s3 при чтении во время чтения.

S3Client s3Client;
S3Object s3Object;

onCreate() {
     s3Client = new AmazonS3Client(new BasicSessionCredentials(
                  Constants.ACCESS_KEY_ID, Constants.SECRET_KEY, Constants.TOKEN
                ));
     object = new S3Object();
}

doinbackground() {
     object = s3Client.getObject(new GetObjectRequest(Constants.getBucket(), id +".png"));
}

/****** add this in your onCreate ******/
AmazonS3Client client = getConnection(userCredentials);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...