2012-05-23 186 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]; 

    }); 
});