2010-05-19 20 views
10

iPhone os'daki nesnel c'yi kullanarak dosyaları doğrudan bir URL'den diske indirmek istiyorum.Nasıl iPhone os üzerinde disk doğrudan dosyaları indirmek için?

Şu anda, bir NSNLConnection kullanarak, dönen NSData'yı bir dosyaya yazarak bir synchronousRequest göndermek için kullanıyorum.

Tüm içeriği (yalnızca küçük parçaları) depolamak için bellek değişkenlerini kullanmadan, veriyi doğrudan diske yazmak için indirme işlemini nasıl değiştirebilirim (yine de, artalan senkronizasyon isteğine sahip, bir arka plan iş parçacığındadır)?

Örnek bir kod takdir edilecektir.

Yanıtlarınız için şimdiden teşekkür ederiz!

+0

'' '' bellekten geçmeden '' sistem çağrısı. Veriler, satır boyunca bir yerde hafızaya alınacaktır. Şimdi, "dosyaya indirilen URL" API'si sağlayan bir kütüphane bulmanız mümkündür, ancak dahili olarak hala bellekte bir arabellek kullanıyordur. –

+0

Bu doğru David, ancak dosyaya yazarken tüm dosya içeriğini bellekte saklamak gerekmiyor, sadece küçük tamponlar. Aradığım şey bu. – favo

cevap

13

Bunu yapabilirsiniz, ancak kurulumu biraz karmaşıktır. İşte ben şöyle yaparım:

Uyarı: Aşağıdaki kod bir tarayıcıda yazılmıştır ve kafamda derlenmiştir. Ayrıca, çok fazla hata işleme yok. Caveat Uygulayıcısı.

//NSURLConnection+DirectDownload.h 
@interface NSURLConnection (DirectDownload) 

+ (BOOL) downloadItemAtURL:(NSURL *)url toFile:(NSString *)localPath error:(NSError **)error; 

@end 

//NSURLConnection+DirectDownload.m 
@implementation NSURLConnection (DirectDownload) 

+ (BOOL) downloadItemAtURL:(NSURL *)url toFile:(NSString *)localPath error:(NSError **)error { 
    NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:url]; 
    //configure the request, or leave it as-is 

    DirectDownloadDelegate * delegate = [[DirectDownloadDelegate alloc] initWithFilePath:localPath]; 
    NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate]; 
    [delegate autorelease]; 
    [request release]; 

    while ([delegate isDone] == NO) { 
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; 
    } 

    [connection release]; 

    NSError * downloadError = [delegate error]; 
    if (downloadError != nil) { 
    if (error != nil) { *error = [[downloadError retain] autorelease]; } 
    return NO; 
    } 

    return YES; 
} 

//DirectDownloadDelegate.h 
@interface DirectDownloadDelegate : NSObject { 
    NSError *error; 
    NSURLResponse * response; 
    BOOL done; 
    NSFileHandle * outputHandle; 
} 
@property (readonly, getter=isDone) BOOL done; 
@property (readonly) NSError *error; 
@property (readonly) NSURLResponse * response; 

@end 

//DirectDownloadDelegate.m 
@implementation DirectDownloadDelegate 
@synthesize error, request, done; 

- (id) initWithFilePath:(NSString *)path { 
    if (self = [super init]) { 
    if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { 
     [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; 
    } 
    [[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil]; 
    outputHandle = [[NSFileHandle fileHandleForWritingAtPath:path] retain]; 
    } 
    return self; 
} 

- (void) dealloc { 
    [error release]; 
    [response release]; 
    [outputHandle closeFile]; 
    [outputHandle release]; 
    [super dealloc]; 
} 

- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)anError { 
    error = [anError retain]; 
    [self connectionDidFinishLoading:connection]; 
} 

- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)someData { 
    [outputHandle writeData:someData]; 
} 

- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)aResponse { 
    response = [aResponse retain]; 
} 

- (void) connectionDidFinishLoading:(NSURLConnection *)connection { 
    done = YES; 
} 

temel fikir normalde asenkron olan standart NSURLConnection oluşturmak, ama sadece bağlantı yapılana kadar kendinizi runloop iplik ile iplik engellemek olmasıdır. Ayrıca, bağlantının doğrudan bir dosyaya gönderdiği tüm verileri borulamak için özel bir url bağlantısı temsilcisi de kullanabilirsiniz.

Artık yapabilirsiniz:

NSError * downloadError = nil; 
BOOL ok = [NSURLConnection downloadItemAtURL:someURL toFile:someFile error:&downloadError]; 
if (!ok) { 
    NSLog(@"ack there was an error: %@", error); 
} else { 
    NSLog(@"file downloaded to: %@", someFile); 
} 
O OS disk dosyasına a` `URL'den bir "kopya veri olmadığı için tam anlamıyla "doğrudan diske" veri indirmek mümkün olacak değil
+1

Çok güzel bir fikir! Senkronize etmek için sonsuz bir döngü (ugh!;)). Bu iyi bir çözüm, çok teşekkür ederim! Eğer gerçekten tamamen tarayıcıda yazdıysanız gerçekten takdire şayan: – favo

+0

dürüst olmak gerekirse, geçen hafta böyle bir şey yapmak zorunda kaldım ve hatırladığım şeyden çıkmıştım ...;) –

+0

Dikkat ederseniz Herhangi bir arayanlar, bu fonksiyonun içinde çalışmak için ana çalışma döngüsü için mutlu olurlar (özellikle, bir olay işleyicisindeyseniz, mevcut olayın işlenmesi tamamlanmadan önce diğer olayları idare edersiniz.). –

İlgili konular