如何判断文件何时完成下载并可以使用?
How to tell when file has finished downloading and ready to use?
我正在从我自己的 Web 服务下载文件 (.json),下载完成后我需要将内容 'unpacked' 放入本地 SQLlite 数据库中。
我知道 NSURLConnection 在另一个线程上异步下载文件以保持主线程打开。问题是当文件下载开始时,主线程显然继续做它正在做的事情——在这种情况下试图将文件的内容加载到数据库中。当发生这种情况时,文件要么不存在,要么存在但尚未完成。
如何运行只有在文件实际完全下载并准备好使用后才将文件内容输入数据库的方法?
-(void)downloadTheFileFrom:(NSString*)url withToken:(NSString*)token
{
NSString *conURL = [NSString stringWithFormat:@"%@/%@", apiURL, url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:conURL]];
[request setHTTPMethod:@"GET"];
[request addValue:@"application/json" forHTTPHeaderField:(@"content-type")];
[request addValue:token forHTTPHeaderField:(@"X-TOKEN")];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[conn scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[conn start];
[self saveJsonToDatabase];
}
将文件保存到数据库的方法:
-(void)saveJsonToDatabase
{
NSString *jsonFileToSave = @"drug.json";
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSError *jsonError = nil;
NSString *jsonFile = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"/content/formulary/files/%@", jsonFileToSave]];
NSData *jsonData = [NSData dataWithContentsOfFile:jsonFile];
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&jsonError];
NSString *formularyTable = [NSString stringWithFormat:@"formulary_%@", [jsonFileToSave stringByDeletingPathExtension]];
FormularyDBManager *formularyDBManagerInstance = [FormularyDBManager new];
[formularyDBManagerInstance insertInto:formularyTable arrayOfDicts:jsonArray];
}
NSURLConnection 的委托方法:
-(void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSString *apiUrl = [NSString stringWithFormat:@"%@",[response URL]];
NSArray *pathComponents = [apiUrl pathComponents];
NSString *areaFolder = [pathComponents objectAtIndex:3];
NSString *fileName = [response suggestedFilename];
NSString *fileType = [fileName pathExtension];
NSString *docsfolderPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *folderPath = [docsfolderPath stringByAppendingString:[NSString stringWithFormat:@"/content/%@/%@", areaFolder, contentType]];
BOOL isDir;
NSFileManager *fileManager= [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:folderPath isDirectory:&isDir])
if(![fileManager createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:NULL])
NSLog(@"FileDownloader - connection - Error: Create folder failed %@", folderPath);
NSString *filePath = [folderPath stringByAppendingPathComponent:fileName];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
connection.file = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
_currentFile = fileName;
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[connection.file writeData:data];
}
-(NSCachedURLResponse *)connection:(FileURLConnection *)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse {
return nil;
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[connection.file closeFile];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"GetData - connection - error - %@", error);
}
如果您使用 NSURLSessionDownloadTask 它将更容易处理,因为它是一个完成块方法。下载完成后,块中的代码将被执行。另外 NSURLConnection 已被弃用。
我会坚持使用 NSURLSession 和 NSURLSessionDownloadTask,因为 NSURLConnection 已被弃用。
NSURLSessionDownloadTask 可以在块中或委托中回答,让我们坚持使用块变体。
// Your request
NSString *conURL = [NSString stringWithFormat:@"%@/%@", apiURL, url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:conURL]];
[request setHTTPMethod:@"GET"];
[request addValue:@"application/json" forHTTPHeaderField:(@"content-type")];
[request addValue:token forHTTPHeaderField:(@"X-TOKEN")];
// Create a simple Session
NSURLSession *session = [NSURLSession sharedSession];
// Create the downloadTask
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable tempLocation, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// this block will be called on a async thread when the task is finished.
// if no error occurred and we got a path lets store the data.
if (!error && tempLocation) {
// I pass the location to your function, so it can read the file.
[self saveJsonToDatabase:tempLocation];
}
}];
[downloadTask resume]; // don't forget to start the task.
任务在完成或失败时调用其块。 tempLocation 中的文件只是临时文件,之后会被删除,如果你想保留它,你需要将它移动到不同的路径。
有关详细信息,您可以阅读有关使用 NSURLSession + Tasks
的苹果文档
我正在从我自己的 Web 服务下载文件 (.json),下载完成后我需要将内容 'unpacked' 放入本地 SQLlite 数据库中。
我知道 NSURLConnection 在另一个线程上异步下载文件以保持主线程打开。问题是当文件下载开始时,主线程显然继续做它正在做的事情——在这种情况下试图将文件的内容加载到数据库中。当发生这种情况时,文件要么不存在,要么存在但尚未完成。
如何运行只有在文件实际完全下载并准备好使用后才将文件内容输入数据库的方法?
-(void)downloadTheFileFrom:(NSString*)url withToken:(NSString*)token
{
NSString *conURL = [NSString stringWithFormat:@"%@/%@", apiURL, url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:conURL]];
[request setHTTPMethod:@"GET"];
[request addValue:@"application/json" forHTTPHeaderField:(@"content-type")];
[request addValue:token forHTTPHeaderField:(@"X-TOKEN")];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[conn scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[conn start];
[self saveJsonToDatabase];
}
将文件保存到数据库的方法:
-(void)saveJsonToDatabase
{
NSString *jsonFileToSave = @"drug.json";
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSError *jsonError = nil;
NSString *jsonFile = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"/content/formulary/files/%@", jsonFileToSave]];
NSData *jsonData = [NSData dataWithContentsOfFile:jsonFile];
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&jsonError];
NSString *formularyTable = [NSString stringWithFormat:@"formulary_%@", [jsonFileToSave stringByDeletingPathExtension]];
FormularyDBManager *formularyDBManagerInstance = [FormularyDBManager new];
[formularyDBManagerInstance insertInto:formularyTable arrayOfDicts:jsonArray];
}
NSURLConnection 的委托方法:
-(void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSString *apiUrl = [NSString stringWithFormat:@"%@",[response URL]];
NSArray *pathComponents = [apiUrl pathComponents];
NSString *areaFolder = [pathComponents objectAtIndex:3];
NSString *fileName = [response suggestedFilename];
NSString *fileType = [fileName pathExtension];
NSString *docsfolderPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *folderPath = [docsfolderPath stringByAppendingString:[NSString stringWithFormat:@"/content/%@/%@", areaFolder, contentType]];
BOOL isDir;
NSFileManager *fileManager= [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:folderPath isDirectory:&isDir])
if(![fileManager createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:NULL])
NSLog(@"FileDownloader - connection - Error: Create folder failed %@", folderPath);
NSString *filePath = [folderPath stringByAppendingPathComponent:fileName];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
connection.file = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
_currentFile = fileName;
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[connection.file writeData:data];
}
-(NSCachedURLResponse *)connection:(FileURLConnection *)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse {
return nil;
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[connection.file closeFile];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"GetData - connection - error - %@", error);
}
如果您使用 NSURLSessionDownloadTask 它将更容易处理,因为它是一个完成块方法。下载完成后,块中的代码将被执行。另外 NSURLConnection 已被弃用。
我会坚持使用 NSURLSession 和 NSURLSessionDownloadTask,因为 NSURLConnection 已被弃用。
NSURLSessionDownloadTask 可以在块中或委托中回答,让我们坚持使用块变体。
// Your request
NSString *conURL = [NSString stringWithFormat:@"%@/%@", apiURL, url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:conURL]];
[request setHTTPMethod:@"GET"];
[request addValue:@"application/json" forHTTPHeaderField:(@"content-type")];
[request addValue:token forHTTPHeaderField:(@"X-TOKEN")];
// Create a simple Session
NSURLSession *session = [NSURLSession sharedSession];
// Create the downloadTask
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable tempLocation, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// this block will be called on a async thread when the task is finished.
// if no error occurred and we got a path lets store the data.
if (!error && tempLocation) {
// I pass the location to your function, so it can read the file.
[self saveJsonToDatabase:tempLocation];
}
}];
[downloadTask resume]; // don't forget to start the task.
任务在完成或失败时调用其块。 tempLocation 中的文件只是临时文件,之后会被删除,如果你想保留它,你需要将它移动到不同的路径。
有关详细信息,您可以阅读有关使用 NSURLSession + Tasks
的苹果文档