【问题标题】:iOS Amazon S3 download large filesiOS Amazon S3 下载大文件
【发布时间】:2012-05-23 20:47:37
【问题描述】:

我是 Amazon S3 的新手,我在从 S3 下载大文件时遇到了困难。

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

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

然后我在设备上尝试了它。现在它似乎只是在随机时间崩溃并且

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

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

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

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

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

任何帮助将不胜感激。

谢谢。

【问题讨论】:

    标签: ios debugging amazon-s3 amazon-web-services


    【解决方案1】:

    我是适用于 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];
    

    更新:我们在 downloading large files with the AWS SDK for iOS 上的 AWS 移动开发人员博客中添加了一篇帖子,其中包含此信息以及其他提示。

    【讨论】:

      【解决方案2】:

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

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

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

      然后重写 -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 来一直释放body。

      这是一个快速而肮脏的修复,因为您仍然有恒定的数据分配、附加然后释放。但是当你处于紧要关头时它会起作用。对于我下载 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
      

      希望对你有帮助。

      【讨论】:

      • 感谢您的帮助。我使用 AWS 实施没有 ASIHTTP。当我使用仅下载的应用程序测试我的 1.5 gig 下载时,它从未崩溃。如果我将该代码放回我的应用程序中,应用程序就会崩溃。所以你认为 LARgeFileS3GetObjectResponse.m 示例解决了这个问题?
      • 我需要一种方法来获取某些项目的数据块,同时同时下载多个文件,因此我通过 ASW S3 源代码进行了快速修复,而不是创建自己的解决方案。您必须对其进行测试,唯一真正的变化是在您使用 S3GetObjectRequest 的位置,您将使用 LargeFileS3GetObjectRequest。对我来说,它总共下载了大约 4gb 的数据,文件从 1mb 到 700mb(在 iPod touch 4g 上测试)。
      • 谢谢,当我回到我的项目中的那个点时,我会试一试。应该在一天左右。如果我遇到问题,我一定会告诉你。再次感谢。
      • 嘿,是时候了。我有几个关于你正在实施的问题。在 LargeFileS3GetObjectRequest 你实现了什么?和 LargeFileS3GetObjectResponse 你实现了其余的委托方法吗?
      • 不需要实现其他任何东西,您只需像往常一样使用 Amazon 的 S3GetObjectResponse/Request 功能,并以这种方式覆盖单个方法以摆脱它,将下载的所有数据保留在 RAM 中。策略是打开一个流,每当您像往常一样接收数据时,您只需将其写入流。这也意味着您将在成功完成下载后获得 NULL 作为数据,因此您可以在收到委托数据时跟踪它的大小。您还可以使用普通的 AWS S3 调用(如 S3GetObjectMetadata)预先获取文件的大小和上次修改的大小。
      【解决方案3】:

      您可能希望通过 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]);
      }
      

      【讨论】:

      • 我不喜欢使用没有维护的东西。
      • 嗯,这是很长一段时间以来最好的。如果您找到具有所有功能(从磁盘流、S3 等)的东西,请告诉我。
      【解决方案4】:
      /* 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];
      
          });
      });
      

      【讨论】:

        猜你喜欢
        • 2018-03-14
        • 2020-05-29
        • 2014-11-28
        • 1970-01-01
        • 2017-02-21
        • 1970-01-01
        • 1970-01-01
        • 2011-02-06
        • 2012-10-10
        相关资源
        最近更新 更多