3

我对 Amazon S3 很陌生,我很难从 S3 下载大文件。

我每次都成功下载了一个 35MB 的文件,但是当文件的大小真的很大,大约 500 MB - 1.7GB 时,应用程序就会崩溃。

在模拟器上尝试时,我会在下载大约 1GB 后出现无法分配区域错误。

所以我在设备上试了一下。现在它似乎只是在随机时间崩溃并且

设备中没有崩溃报告,因此我在调试这个问题时遇到了问题。

一开始我以为是设备,甚至是模拟器。但我不太确定。

有人提到 S3 框架偶尔会随机超时下载大文件。会是这样吗?

我通过打开一个寻找到最后的数据文件来构建文件,添加数据,然后关闭文件直到下载完成。

我不确定如何调试这个问题。

任何帮助,将不胜感激。

谢谢你。

4

4 回答 4

3

我是适用于 iOS 的 AWS 开发工具包的维护者。我们最近修补了 S3GetObjectResponse 以允许将数据直接流式传输到磁盘,而无需将响应数据保存在内存中。

S3GetObjectResponse.m

要启用此功能,您只需在创建请求时设置流:

NSOutputStream *outputStream = [[[NSOutputStream alloc] initToFileAtPath:FILE_NAME append:NO] autorelease];
[outputStream open];
S3GetObjectRequest *getObjectRequest = [[[S3GetObjectRequest alloc] initWithKey:FILE_NAME withBucket:BUCKET_NAME] autorelease];
getObjectRequest.outputStream = outputStream;
[s3 getObject:getObjectRequest];

更新:我们在 AWS 移动开发人员博客中添加了一篇关于使用适用于 iOS 的 AWS 开发工具包下载大文件的帖子,其中包括此信息以及其他提示。

于 2012-10-10T18:16:38.810 回答
1

S3GetObjectRequest 具有 NSMutableData* 主体,其中附加了它下载的所有数据。

对于大文件,随着下载的进行,数据会不断附加,并且超过了 90MB 的 VM 限制,然后应用程序被 iOS 杀死。

快速而肮脏的解决方法是创建自己的 S3GetObjectRequest 和 S3GetObjectResponse 类。AWS 框架根据请求的类名称实例化响应(请求的类名称没有最后 7 个字符“请求”并附加“响应”,并尝试实例化该名称的新类)。

然后覆盖-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data以一直释放正文。

这是一个快速而肮脏的修复,因为您仍然有恒定的数据分配、附加然后释放。但是当你处于紧要关头时它会起作用。对于我下载 150-700mb 文件的使用情况,这个简单的 hack 将应用程序的内存使用量平均保持在 2.55mb,+/- 0.2mb。

正如 ASIHTTP 库的作者所说,它不再被维护。

请求 - LargeFileS3GetObjectRequest.h

@interface LargeFileS3GetObjectRequest : S3GetObjectRequest
@end

请求 - LargeFileS3GetObjectRequest.m

@implementation LargeFileS3GetObjectRequest
@end

响应 - LargeFileS3GetObjectResponse.h

@interface LargeFileS3GetObjectResponse : S3GetObjectResponse
@end

响应 - LargeFileS3GetObjectResponse.m

@implementation LargeFileS3GetObjectResponse

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    // allow original implementation to send data to delegates
    [super connection:connection didReceiveData:data];

    // release body and set it to NULL so that underlying implementation doesn't
    // append on released object, but instead allocates new one
    [body release];
    body = NULL;
}
@end

希望能帮助到你。

于 2012-06-26T09:32:25.573 回答
0

您可能希望通过 ASIHTTPRequest 将数据流式传输到您的应用程序

http://allseeing-i.com/ASIHTTPRequest/S3

NSString *secretAccessKey = @"my-secret-access-key";
NSString *accessKey = @"my-access-key";
NSString *bucket = @"my-bucket";
NSString *path = @"path/to/the/object";

ASIS3ObjectRequest *request = [ASIS3ObjectRequest requestWithBucket:bucket key:path];
[request setSecretAccessKey:secretAccessKey];
[request setAccessKey:accessKey];
[request startSynchronous];
if (![request error]) {
    NSData *data = [request responseData];
} else {
    NSLog(@"%@",[[request error] localizedDescription]);
}
于 2012-05-23T22:40:09.870 回答
0
/* Set up the Amazon client */
_s3 = [[AmazonS3Client alloc] initWithAccessKey:k_Amazon_ACCESS_KEY_ID withSecretKey:k_Amazon_SECRET_KEY];
_s3.endpoint = [AmazonEndpoints s3Endpoint:SA_EAST_1];

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{

    /* Open a file stream for the download */
    NSOutputStream *outputStream = [[NSOutputStream alloc] initToFileAtPath:[DOCUMENTS_DIRECTORY stringByAppendingPathComponent:k_Amazon_Video_Local_File_Name] append:NO];
    [outputStream open];

    /* Set up the s3 get object */

    S3GetObjectRequest *getVideoRequest = [[S3GetObjectRequest alloc] initWithKey:k_Amazon_Video_Path withBucket:@""];

    /* Set the stream */

    getVideoRequest.outputStream = outputStream;

    /* Get the response from Amazon */

    S3GetObjectResponse *getObjectResponse = [_s3 getObject:getVideoRequest];

    dispatch_async(dispatch_get_main_queue(), ^{

        if(getObjectResponse.error != nil)
        {
            NSLog(@"S3 Error: %@", getObjectResponse.error);
        }
        else
        {
            NSLog(@"S3 - Video download complete and successful");
            [[NSUserDefaults standardUserDefaults] setBool:YES forKey:k_Amazon_Video_Downloaded];
        }

        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];

    });
});
于 2013-06-07T08:24:19.480 回答