2012-05-23 70 views
3

我是亚马逊S3的新手,我无法从S3下载大文件。iOS亚马逊S3下载大文件

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

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

然后我在设备上试了一下。现在它似乎只是在随机时间崩溃和

没有崩溃报告放在设备中,因此我有调试这个问题的问题。

起初我以为是设备,甚至是模拟器。但我不确定。

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

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

我不知道如何调试此问题。

任何帮助,将不胜感激。

谢谢。

回答

1

S3GetObjectRequest有NSMutableData到数据流,以您的应用程序*身体哪里附加所有它下载数据。

对于下载过程中的大文件,数据会不断添加,并超过90MB的VM限制,然后应用程序被iOS杀死。

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

然后覆盖- (无效)连接:(NSURLConnection *)连接didReceiveData:(NSData *)数据一直释放正文。

这是快速和肮脏的修复,只是因为你仍然有不断的数据分配,追加和释放。但是当你处于困境时它会起作用。对于我下载150-700MB文件的用法,这个简单的黑客程序使得应用程序的内存使用量平均为2.55mb,+/- 0.2mb。

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

请求 - LargeFileS3GetObjectRequest.h

@interface LargeFileS3GetObjectRequest : S3GetObjectRequest 
@end 

请求 - LargeFileS3GetObjectRequest。米

@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 

希望它能帮助。

+1

感谢您的帮助。我正在使用AWS实现,没有ASIHTTP。当我用一款只下载了它的应用测试了我的1.5 gig下载时,它从未崩溃。如果我把这些代码放回到应用程序中,应用程序就会崩溃。所以你认为那里的LArgeFileS3GetObjectResponse.m例子解决了这个问题? – user1086377

+0

我需要一种方法来获取某个项目的数据块,同时下载多个文件,因此我通过ASW S3源代码进行了快速修复,而不是创建自己的解决方案。你将不得不测试它,只有真正的改变是你在使用S3GetObjectRequest的位置,你将使用LargeFileS3GetObjectRequest。对我来说,它总共下载了4GB的数据,文件从1MB到700MB(在iPod touch 4g上测试)。 –

+0

谢谢,当我回到我的项目中的这一点时,我会给它一个镜头。应该在一天左右。如果遇到问题,我一定要问你。再次感谢。 – user1086377

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]); 
} 
+0

我不喜欢使用不被维护的东西。 – user1086377

+0

这是很长一段时间以来最好的。让我知道如果你发现它的所有功能(从磁盘,S3流等)的东西。 –

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移动开发者博客上downloading large files with the AWS SDK for iOS包括这个信息以及其他技巧。

+0

是的,效果很好。 – Zsolt

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

    }); 
});