我需要从服务器下载大文件(即> 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
谢谢,
更新 这是因为我的可下载文件位于具有下载限制的共享主机中。我将该文件移动到工作正常的专用服务器后。而且我也尝试下载一些其他文件,如来自其他网站的视频,也工作正常。 因此,如果您遇到部分下载等问题,请不要只使用代码,检查服务器
答案 0 :(得分:23)
您当前正在将所有下载的数据保存在NSMutableData对象中,该对象保留在设备的RAM中。这将取决于设备和可用内存,在某些时候触发内存警告甚至崩溃。
要使这么大的下载工作,您必须将所有下载的数据直接写入文件系统。
-(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];
}
答案 1 :(得分:7)
我遇到了同样的问题,似乎我发现了一些解决方案。
在头文件中声明:
NSMutableData *webData;
NSFileHandle *handleFile;
在downloadFileFromURL
上的.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];
}
}
当connectionDidFinishLoading
上的下载完成时,添加以下行以写入文件并释放连接:
[handleFile writeData:webData];
[webData release];
[theConnection release];
我现在正在尝试,希望它有效..
答案 2 :(得分:2)
这是因为我的可下载文件位于具有下载限制的共享主机中。我将该文件移动到工作正常的专用服务器后。而且我也尝试下载一些其他文件,比如来自其他一些网站的视频,这些文件也运行良好。
因此,如果您遇到部分下载等问题,请不要只使用代码,也请检查服务器。
答案 3 :(得分:1)
如果您愿意使用asi-http-request,那就更容易了。
使用asi。
查看https://github.com/steipete/PSPDFKit-Demo的工作示例这很容易:
// 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]);
}];