使用ASIHTTPRequest和Rackspace云文件下载不完整的文件

时间:2012-03-05 05:27:24

标签: ios nsurlconnection asihttprequest rackspace-cloud rackspace

我正在从Rackspace云文件下载mp3文件,对于大型文件,我遇到了下载成功完成但文件尚未完全下载的问题。例如,40 MB mp3文件(01:00:00持续时间)下载为4.5 MB mp3文件(00:10:30持续时间)。这不会一直发生。

  1. 有关正在发生的事情的任何指示?
  2. 为什么会这样,我该如何解决这个问题?
  3. 如何构建一个简单的校验和逻辑来检查文件是否已完全下载?
  4. 以下是我创建和发送异步请求的方法:

    ASIHTTPRequest *request;
    request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:urlString]];
    [request setShouldAttemptPersistentConnection:NO]; 
    [request setAllowResumeForFileDownloads:YES];
    [request setDownloadProgressDelegate:self];
    [request setShouldContinueWhenAppEntersBackground:YES];
    [request setUserInfo:userInfo];
    [request setDownloadDestinationPath:downloadPath];
    [request setTemporaryFileDownloadPath:[NSString stringWithFormat:@"%@.download", downloadPath]];
    
    [self.networkQueue addOperation:request];
    [self.networkQueue go];
    

    注意我正在使用具有4个并发下载的网络队列。

    感谢。

    编辑(2012年3月5日,星期三,下午03:25)

    因此,进一步调查显示ASINetworkQueue正在调用requestDidFinishSelector委托方法而不是requestDidFailSelectorASIHTTPRequest对象返回的状态代码为206, HTTP/1.1 206 Partial Content方法requestDidFinishSelector。状态代码应为200, HTTP/1.1 200 OK

    我还是不知道为什么!我仍然不知道如何解决这个问题。似乎我将不得不删除部分下载的文件并再次开始下载过程。此时,删除了临时文件%@.download,并将此部分下载的文件放在目标路径中。

1 个答案:

答案 0 :(得分:1)

所以,这就是我最终做的事情,希望这足够(解决问题)。

以下是我创建网络队列的方法:

- (ASINetworkQueue *)networkQueue {

    if (!_networkQueue) {
        _networkQueue = [[ASINetworkQueue alloc] init];
        [_networkQueue setShowAccurateProgress:YES];
        [_networkQueue setRequestDidFinishSelector:@selector(contentRequestDidSucceed:)];
        [_networkQueue setRequestDidFailSelector:@selector(contentRequestDidFail:)];
        [_networkQueue setShouldCancelAllRequestsOnFailure:NO];
        [_networkQueue setDelegate:self];
    }

    return _networkQueue;
}

这就是我的contentRequestDidSucceed:方法所做的事情:

- (void)contentRequestDidSucceed:(ASIHTTPRequest *)request {
    // ASIHTTPRequest doesn't use HTTP status codes (except for redirection), 
    // so it's up to us to look out for problems (ex: 404) in the requestDidFinishSelector selector. 
    // requestDidFailSelector will be called only if there is the server can not be reached 
    // (time out, no connection, connection interrupted, ...)

    // In certain cases ASIHTTPRequest/ASINetworkQueue calls the delegate method requestDidFinishSelector,
    // instead it should call requestDidFailSelector. I've encountered this specific case with status code 206 (HTTP/1.1 206 Partial Content). In this case the file was not completely downloaded, so we'll have to re-process the request.
    if ([request responseStatusCode] != 200) {
        NSLog(@" ");
        NSLog(@"======= BEEP =======");
        NSLog(@" ");

        // We're double checking that the file was indeed not downloaded completely!
        // During internal testing, we encountered a case where download was successful
        // but we received 206 as the response code (maybe we received the cached value).
        unsigned long long progress = [request totalBytesRead] + [request partialDownloadSize];
        unsigned long long total = [request contentLength] + [request partialDownloadSize];

        if (progress != total) {
            NSString *downloadPath = [request downloadDestinationPath];
            NSString *temporaryDownloadPath = [self temporaryPathForFile:downloadPath];

            // Move the file at destination path to the temporary destination path (back again)    
            NSError *moveError = nil;
            [[[[NSFileManager alloc] init] autorelease] moveItemAtPath:downloadPath 
                                                                toPath:temporaryDownloadPath 
                                                                 error:&moveError];

            if (moveError) {
                NSLog(@"Failed to move file from '%@' to '%@'", downloadPath, temporaryDownloadPath);

                NSError *removeError = nil;
                [ASIHTTPRequest removeFileAtPath:downloadPath error:&removeError];

                if (removeError) {
                    NSLog(@"Failed to remove file from '%@'", downloadPath);
                }
            }

            // Call the requestDidFailSelector method
            [self contentRequestDidFail:request];

            // Don't continue
            return;   
        }        
    }

    // TODO: Process successful request!
    // . . .
}

如果有更好的方法来解决这个问题,请告诉我。