3

私は Amazon S3 を初めて使用し、S3 から大きなファイルをダウンロードするのに苦労しています。

毎回 35MB のファイルを正常にダウンロードしましたが、ファイルのサイズが 500 MB ~ 1.7GB と非常に大きくなると、アプリケーションがクラッシュします。

シミュレーターを試してみると、約 1GB のダウンロード後に領域を割り当てられないというエラーが表示されます。

それで、私はデバイスでそれを試しました。今ではランダムな時間にクラッシュするようで、

クラッシュ レポートがデバイスに保存されていないため、この問題のデバッグに問題があります。

最初は、デバイスかシミュレーターだと思っていました。しかし、よくわかりません。

大きなファイルの場合、S3 フレームワークがダウンロードをランダムにタイムアウトさせることがあると誰かが言いました。これは事実でしょうか?

最後までシークするデータ ファイルを開き、データを追加してから、ダウンロードが完了するまでファイルを閉じて、ファイルを作成しています。

この問題をデバッグする方法がわかりません。

どんな助けでも大歓迎です。

ありがとうございました。

4

4 に答える 4

3

私は AWS SDK for iOS のメンテナーです。最近、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 SDK for iOS を使用した大きなファイルのダウンロードに関する投稿を AWS モバイル開発者ブログに追加しました。

于 2012-10-10T18:16:38.810 に答える
1

S3GetObjectRequest には、ダウンロードするすべてのデータを追加する NSMutableData* 本体があります。

大きなファイルの場合、ダウンロードが進行するにつれてデータが絶えず追加され、VM の制限である 90MB を超えると、iOS によってアプリが強制終了されます。

手っ取り早い回避策は、独自の S3GetObjectRequest および S3GetObjectResponse クラスを作成することです。AWS フレームワークは、リクエストのクラス名に基づいてレスポンスをインスタンス化します (最後の 7 文字「リクエスト」を除いたリクエストのクラス名に「レスポンス」を追加し、その名前の新しいクラスをインスタンス化しようとします)。

次に、-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)dataをオーバーライドして、常にボディを解放します。

一定のデータ割り当て、追加、および解放がまだ行われているため、これは簡単で汚い修正です。でもピンチの時は効きます。150 ~ 700 MB のファイルをダウンロードする私の使用法では、この単純なハックにより、アプリのメモリ使用量が平均 2.55 MB、+/- 0.2 MB に維持されました。

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
/* 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 に答える
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 に答える