1

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

  1. 关于发生了什么的任何指示?
  2. 为什么会发生这种情况,我该如何解决这个问题?
  3. 如何构建一个简单的校验和逻辑来检查文件是否已完全下载?

这是我创建和发送异步请求的方式:

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 日星期一,下午 3:25)

因此,进一步的调查表明,这ASINetworkQueue是调用requestDidFinishSelector委托方法而不是requestDidFailSelector. ASIHTTPRequest对象返回的状态码206, HTTP/1.1 206 Partial ContentrequestDidFinishSelector方法中。状态码应该是200, HTTP/1.1 200 OK.

我还是不知道为什么!我仍然不知道如何解决这个问题。看来我必须删除部分下载的文件并重新开始下载过程。此时临时文件 ie%@.download被删除,并将这个部分下载的文件放在目标路径。

4

1 回答 1

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!
    // . . .
}

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

于 2012-03-07T04:46:56.960 回答