Android AWS s3 SDK下载抛出“Socket is closed”异常或提前终止

时间:2011-12-22 05:04:38

标签: android amazon-s3

我正在尝试使用AWS Android SDK 1.0.4或1.0.3从S3下载对象。

这是我的代码:

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设备上。它发生在WiFi和3G上。

有什么想法吗?

PS>对象大约250k

4 个答案:

答案 0 :(得分:4)

问题是客户端正在收集垃圾。要修复它,您需要保持对S3Client的显式引用。

错误的流程如下:

  1. 程序获得S3客户端
  2. 程序从客户端获取S3对象。
  3. 程序从s3Object获取一个inputStream,它通过客户端获取它。
  4. 垃圾收集运行,由于没有对客户端的引用,它会收集Garbage,随机关闭inputStream。
  5. IMO,亚马逊这是一个非常糟糕的错误。为什么S3对象输入流没有引用回客户端对我来说是一个谜。

    以下是AWS论坛上的主题:https://forums.aws.amazon.com/thread.jspa?threadID=83326

答案 1 :(得分:2)

你可能已经解决了这个问题,但我找不到正确的答案,最后我自己搞清楚了,所以这就解决了:

getObjectContent方法文档非常清楚关闭InputStream:

  

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

     

获取包含此对象内容的输入流。调用者应尽快关闭此输入流,因为对象内容不会缓存在内存中,而是直接从Amazon S3流式传输。

你犯的是和我使用InputStream(S3Object)一样的错误,好像闭包是透明的。

我猜你需要从S3获取一个图像才能在Android上使用,所以这里有一个返回Bitmap的示例方法。它确实适用于任何类型的输入。

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

以防万一,不要忘记在不同的线程上执行此操作,然后再执行UI。

祝你好运,

答案 2 :(得分:1)

好吧,看来你并不孤单。在帖子回答中接受你的问题。

How to write an S3 object to a file?

我会尝试循环内容,就像上面问题中的答案一样。缓冲很好,但是......

你也可以尝试不使用IOUtil,毕竟java中还有其他选项。

答案 3 :(得分:0)

无需继续重新初始化s3。

onCreate中,拨打电话以初始化s3Objects3Client

然后使用asynctask中的来电。这样,您的s3Client将保留相同的数据,并且在执行while读取时永远不会关闭与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);