Iphone NSURLConnection下载大文件(>;40MB)

Iphone NSURLConnection下载大文件(>;40MB),iphone,ios,file,download,Iphone,Ios,File,Download,我需要从服务器下载大文件(即>40MB)到我的应用程序,该文件将是ZIP或PDF格式。我使用NSURLConnection实现了这一点,如果文件较小,那么它可以很好地工作,如果它下载了部分填充,并且执行已经停止。例如,我试图下载36MB的PDF文件,但只下载了16MB。请帮我知道原因?如何修复它 供参考: 实现文件 #import "ZipHandlerV1ViewController.h" @implementation ZipHandlerV1ViewController - (void)d

我需要从服务器下载大文件(即>40MB)到我的应用程序,该文件将是ZIP或PDF格式。我使用NSURLConnection实现了这一点,如果文件较小,那么它可以很好地工作,如果它下载了部分填充,并且执行已经停止。例如,我试图下载36MB的PDF文件,但只下载了16MB。请帮我知道原因?如何修复它

供参考: 实现文件

#import "ZipHandlerV1ViewController.h"
@implementation ZipHandlerV1ViewController
- (void)dealloc
{
    [super dealloc];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}
 - (void)viewDidLoad
 {
     UIView *mainView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 400, 400)];
     [mainView setBackgroundColor:[UIColor darkGrayColor]];

     UIButton *downloadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
     [downloadButton setFrame:CGRectMake(50, 50, 150, 50)];
     [downloadButton setTitle:@"Download File" forState:UIControlStateNormal];
     [downloadButton addTarget:self action:@selector(downloadFileFromURL:) forControlEvents:UIControlEventTouchUpInside];
     [mainView addSubview:downloadButton];

     [self setRequestURL:@"http://www.mobileveda.com/r_d/mcps/optimized_av_allpdf.pdf"];
     [self.view addSubview:mainView];

     [super viewDidLoad];
 }

- (void)viewDidUnload
{
    [super viewDidUnload];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}


-(void) setRequestURL:(NSString*) requestURL {
    url = requestURL;
}

-(void) downloadFileFromURL:(id) sender {
    NSURL *reqURL =  [NSURL URLWithString:url];

    NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:reqURL];
    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
    if (theConnection) {
       webData = [[NSMutableData data] retain];
    } else {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error !" message:@"Error has occured, please verify internet connection"  delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];

        [alert show];
        [alert release];
    }
}

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [webData setLength:0]; 
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [webData appendData:data];
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
   NSString *fileName = [[[NSURL URLWithString:url] path] lastPathComponent];
    NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *folder = [pathArr objectAtIndex:0];

    NSString *filePath = [folder stringByAppendingPathComponent:fileName];
    NSURL *fileURL = [NSURL fileURLWithPath:filePath];
    NSError *writeError = nil;

    [webData writeToURL: fileURL options:0 error:&writeError];
    if( writeError) {
        NSLog(@" Error in writing file %@' : \n %@ ", filePath , writeError );
        return;
    }
    NSLog(@"%@",fileURL);
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error !" message:@"Error has occured, please verify internet connection.."  delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];

    [alert show];
    [alert release];

}

@end
头文件:

#import <UIKit/UIKit.h>
@interface ZipHandlerV1ViewController : UIViewController {
    NSMutableData *webData;
    NSString *url;
}
-(void) setRequestURL:(NSString*) requestURL;
@end
#导入
@接口ZipHandlerV1ViewController:UIViewController{
NSMutableData*webData;
NSString*url;
}
-(void)setRequestURL:(NSString*)requestURL;
@结束
谢谢,

更新: 这是因为我的可下载文件位于共享主机中,具有下载限制。在我将该文件移动到专用服务器后,该服务器工作正常。我还试着从其他网站下载一些其他文件,比如视频,效果也不错。
因此,如果您遇到部分下载之类的问题,不要只坚持使用代码,还要检查服务器

您当前正在将所有下载的数据保存在设备RAM中的NSMutableData对象中。这将根据设备和可用内存的不同,在某个时候触发内存警告甚至崩溃

要使如此大的下载量正常工作,您必须将所有下载的数据直接写入文件系统

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{
   //try to access that local file for writing to it...
   NSFileHandle *hFile = [NSFileHandle fileHandleForWritingAtPath:self.localPath];
   //did we succeed in opening the existing file?
   if (!hFile) 
   {   //nope->create that file!
       [[NSFileManager defaultManager] createFileAtPath:self.localPath contents:nil attributes:nil];
       //try to open it again...
       hFile = [NSFileHandle fileHandleForWritingAtPath:self.localPath];
   }
   //did we finally get an accessable file?
   if (!hFile)
   {   //nope->bomb out!
       NSLog("could not write to file %@", self.localPath); 
       return;
   }
   //we never know - hence we better catch possible exceptions!
   @try 
   {
       //seek to the end of the file
       [hFile seekToEndOfFile];
       //finally write our data to it
       [hFile writeData:data];
   }
   @catch (NSException * e) 
   {
       NSLog("exception when writing to file %@", self.localPath); 
       result = NO;
   }
   [hFile closeFile];
}

这是因为我的可下载文件位于共享主机中,具有下载限制。在我将该文件移动到专用服务器后,该服务器工作正常。我还试着从其他网站下载一些其他文件,比如视频,效果也不错


因此,如果您遇到部分下载之类的问题,不要只坚持使用代码,还要检查服务器。

如果您愿意使用asi http请求,这将非常简单

查看asi的工作示例

就这么简单:

    // create request
    ASIHTTPRequest *pdfRequest = [ASIHTTPRequest requestWithURL:self.url];
    [pdfRequest setAllowResumeForFileDownloads:YES];
    [pdfRequest setNumberOfTimesToRetryOnTimeout:0];
    [pdfRequest setTimeOutSeconds:20.0];
    [pdfRequest setShouldContinueWhenAppEntersBackground:YES];
    [pdfRequest setShowAccurateProgress:YES];
    [pdfRequest setDownloadDestinationPath:destPath];

    [pdfRequest setCompletionBlock:^(void) {
        PSELog(@"Download finished: %@", self.url);

        // cruel way to update
        [XAppDelegate updateFolders];
    }];

    [pdfRequest setFailedBlock:^(void) {
        PSELog(@"Download failed: %@. reason:%@", self.url, [pdfRequest.error localizedDescription]);
    }];

我也有同样的问题,似乎我找到了一些解决办法

在头文件中声明:

NSMutableData *webData;
NSFileHandle *handleFile;
下载文件fromURL
上的.m文件中,当您获得连接时,启动NSFileHandle:

if (theConnection) {

        webData = [[NSMutableData data] retain];

        if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
            [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
        }

        handleFile = [[NSFileHandle fileHandleForWritingAtPath:filePath] retain];
    }
然后在
didReceiveData
中,将数据写入磁盘,而不是将数据追加到内存中,如下所示:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

    [webData appendData:data];

    if( webData.length > SOME_FILE_SIZE_IN_BYTES && handleFile!=nil) {          
        [handleFile writeData:recievedData];
        [webData release];
        webData =[[NSMutableData alloc] initWithLength:0];
    }
}
当下载在
connectiondFinishLoading
上完成时,添加以下行以写入文件并释放连接:

[handleFile writeData:webData];
[webData release];
[theConnection release];

我现在正在尝试,希望它能工作。

即使在做了您提到的更改之后,它也只下载了6.4MB的39MB文件,为什么会这样?有内存限制吗?,,我在模拟器和iPad设备上都试过了。每次调用didReceiveData时,都会覆盖该文件。@Vova你是对的,我的示例只是一个提示,没有完全满足需要。我改变了这一点,现在它对所有可能的情况都格外小心。@直到我如何获得self.localPath?谢谢Steipet,是的,我现在使用ASIHttpRequest已经一周了,而且我是iPhone开发人员。我还有一个疑问,那就是如何暂停和恢复下载,以及如何发现整个文件下载成功与否?ASIHttpRequest中是否有可能?再次感谢..我不确定这是内置的-您可能需要重写ASIHttpRequest来完成此操作。这是真的。我目前正在写一篇关于AFNetworking的文章。希望他们能将其与1.0集成。我不知道你为什么要使用NSMutableData而不是仅仅使用NSFileHandle,但我可以举个例子,将一个700MB的文件下载到我的iPad上,而从不将任何数据存储在内存中。谢谢@JosephDeCarlo,拥有NSMutableData的一个很好的理由是减少I/O操作的数量。我想这取决于您尝试下载的文件的大小和资源限制。[handleFile writeData:ReceiveDdata];->[handleFile writeData:webData]?