iOS Amazon S3下载大型文件

iOS Amazon S3下载大型文件,ios,debugging,amazon-s3,amazon-web-services,Ios,Debugging,Amazon S3,Amazon Web Services,我是AmazonS3的新手,从S3下载大文件时遇到困难 我已经成功下载了一个每次35MB的文件,但是当文件的大小真的很大,大约在500MB-1.7GB时,应用程序崩溃了 当在模拟器上尝试时,我会在大约1GB的下载后得到无法分配区域错误 然后我在设备上试了一下。现在它似乎只是在一个随机的时间和时间崩溃 没有在设备中放入崩溃报告,因此我在调试此问题时遇到问题 起初我以为是设备,甚至是模拟器。但我不是很确定 有人提到,S3框架偶尔会为大文件随机超时下载。会是这样吗 我通过打开一个数据文件来构建该文件,

我是AmazonS3的新手,从S3下载大文件时遇到困难

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

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

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

没有在设备中放入崩溃报告,因此我在调试此问题时遇到问题

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

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

我通过打开一个数据文件来构建该文件,该文件的结尾是查找、添加数据,然后关闭该文件,直到下载完成

我不知道如何调试这个问题

任何帮助都将不胜感激


谢谢。

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


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

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

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

然后覆盖-(无效)连接:(NSURLConnection*)连接DIRECEIVEDATA:(NSData*)数据以始终释放身体

这是一个快速而肮脏的解决方案,因为您仍然有固定的数据分配、附加和发布。但它在你有困难的时候起作用。对于我下载150-700mb文件的使用,这个简单的黑客将应用程序的内存使用保持在平均2.55mb+/-0.2mb

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

Request-LargeFileS3GetObjectRequest.h

@interface LargeFileS3GetObjectRequest : S3GetObjectRequest
@end
Request-LargeFileS3GetObjectRequest.m

@implementation LargeFileS3GetObjectRequest
@end
Response-LargeFileS3GetObjectResponse.h

@interface LargeFileS3GetObjectResponse : S3GetObjectResponse
@end
Response-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

希望有帮助。

我是用于iOS的AWS SDK的维护人员。我们最近修补了S3GetObjectResponse,允许直接将数据流传输到磁盘,而无需将响应数据保存在内存中

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

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 Mobile Developer的博客上添加了一篇文章,其中包括此信息以及其他提示。

感谢您的帮助。我使用的是AWS实现no-ASIHTTP。当我用一个只下载一次的应用程序测试我的1.5 gig下载时,它从未崩溃。如果我把代码放回我的应用程序中,应用程序就会崩溃。因此,您认为LArgeFileS3GetObjectResponse.m示例解决了这个问题?我需要一种方法,在同时下载多个文件的同时,为某个项目获取数据块,因此我通过ASW S3源代码进行了此快速修复,而不是创建我自己的解决方案。您必须对其进行测试,唯一真正的变化是,在使用S3GetObjectRequest的位置,您将使用LargeFileS3GetObjectRequest。对我来说,它在下载总共4gb的数据时起作用,文件大小从1MB到700mb(在iPodtouch4G上测试)。谢谢,当我回到我的项目中时,我会试一试。应该在一天左右。如果我遇到问题,我一定会通知你的。再次感谢。嘿,是时候了。我有几个关于你的实施的问题。在LargeFileS3GetObjectRequest中,您实现了什么?大文件3GetObjectResponse是否实现了其余的委托方法?不需要实现任何其他方法,您只需像往常一样使用Amazon的S3GetObjectResponse/Request功能,并以这种方式重写单个方法,以摆脱它,将下载的所有数据保留在RAM中。该策略是打开一个流,每当您像通常一样接收数据时,您只需将其写入流。这也意味着,在成功完成下载后,您将获得NULL作为数据,所以您可以在收到委托中的数据时跟踪它的大小。您还可以使用正常的AWS S3调用(如S3GetObjectMetadata)预先确定文件大小和最后修改。我不喜欢使用未维护的东西。这是很长一段时间以来最好的。如果你发现了它的所有特性(来自磁盘的流、S3等),请告诉我。
/* 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];

    });
});
/* 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];

    });
});