2011-06-02 20 views
17

Necesito descargar un archivo grande (es decir> 40MB) a mi aplicación del servidor, este archivo será ZIP o PDF. Lo logré utilizando NSURLConnection, que funciona bien si el archivo es más pequeño, de lo contrario, descarga una parte del relleno y la ejecución se detiene. por ejemplo, traté de descargar un archivo PDF de 36 MB, pero solo descargué 16 MB. pls me ayuda a saber la razón? ¿Como arreglarlo?NSURLConnection descargar archivo grande (> 40MB)

FYI: Implementación del archivo

#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 

del encabezado del archivo:

#import <UIKit/UIKit.h> 
@interface ZipHandlerV1ViewController : UIViewController { 
    NSMutableData *webData; 
    NSString *url; 
} 
-(void) setRequestURL:(NSString*) requestURL; 
@end 

Gracias,

Actualizado: Esto sucede debido a mi archivo descargable estaba en alojamiento compartido que tiene las limitaciones de descarga. Después de que moví ese archivo al servidor dedicado que funciona bien. y también traté de descargar algunos otros archivos, como videos de otros sitios, que también funcionan bien. Por lo tanto, si usted tiene un problema como descarga parcial, no sólo se pegan con el código, compruebe el servidor demasiado

Respuesta

2

Esto sucede porque mi archivo descargable estaba en el alojamiento compartido que tiene las limitaciones de descarga. Después de que moví ese archivo al servidor dedicado que funciona bien. y también traté de descargar algunos otros archivos, como videos de otros sitios, que también funcionan bien.

Por lo tanto, si tiene problemas como la descarga parcial, no se quede solo con el código, consulte también el servidor.

23

Usted está manteniendo actualmente todos los datos descargados en un objeto NSMutableData que se mantiene dentro de la RAM de su dispositivo. Dependiendo del dispositivo y la memoria disponible, en algún momento se activará una advertencia de memoria o incluso un bloqueo.

Para obtener descargas tan grandes para trabajar, tendrá que escribir todos los datos descargados directamente en el sistema de archivos.

-(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]; 
} 
+0

incluso después de hacer los cambios que mencionó, descarga solo 6.4MB de un archivo de 39MB, ¿Por qué sucede esto? ¿hay alguna limitación de memoria? .., lo probé tanto en el simulador como en el dispositivo iPad. – Jayabal

+0

Esto debe sobrescribir el archivo cada vez que se invoque a fromReceiveData. –

+1

@Vova, tiene razón, mi ejemplo era solo una pista y no cubría completamente las necesidades. Cambié eso y ahora se necesita un cuidado extra para todas las situaciones posibles. – Till

1

Si está dispuesto a utilizar asi-http-request, es mucho, mucho más fácil.

Consulte https://github.com/steipete/PSPDFKit-Demo para obtener un ejemplo de trabajo con asi.

Es tan fácil como esto:

// 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]); 
    }]; 
+0

Gracias steipete, ahora estoy usando ASIHttpRequest durante la última semana, y soy nuevo en el desarrollo de iPhone. Tengo otra duda, ¿cómo detener y reanudar la descarga y cómo podemos descubrir que todo el archivo se ha descargado correctamente o no? ¿Es posible en ASIHttpRequest? Gracias de nuevo. – Jayabal

+0

No estoy seguro de que esté integrado; puede que tenga que anular ASIHttpRequest para hacerlo. – steipete

+3

-1 Parece que ASIHTTPRequest ya no se está trabajando. – MobileOverlord

7

que tenían el mismo problema, y ​​parece que he descubierto alguna solución.

En el archivo de cabecera declaran:

NSMutableData *webData; 
NSFileHandle *handleFile; 

En su.m archivo en downloadFileFromURL cuando llegue a la conexión de iniciar el 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]; 
    } 

después en didReceiveData en lugar de añadir datos a la memoria escribir en el disco, así:

- (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]; 
    } 
} 

cuando el acabado de su descarga en connectionDidFinishLoading añadir estas líneas para escribir el archivo y liberar conexión:

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

estoy tratando ahora mismo, espero que funcione ..

+0

No estoy seguro de por qué está utilizando NSMutableData en lugar de simplemente usar NSFileHandle, pero pude tomar este ejemplo y descargar un archivo de 700MB a mi iPad sin almacenar ninguno de los datos en la memoria. ¡Gracias! –

+0

@JosephDeCarlo, una buena razón para tener NSMutableData es reducir el número de operaciones de E/S. –

+0

Supongo que depende del archivo de tamaño que está intentando descargar y cuáles son sus limitaciones de recursos. –

Cuestiones relacionadas