更新没有XML的sqlite数据库

我的应用程序需要来自sqlite数据库的数据。 它将附带这个数据库的一个版本,但我需要定期更新(最可能每月一次)。 通常情况下,我一直在通过我设置的一堆web服务将XML应用的其他部分的更新发送给XML,但是现在我正在使用的这个特定的数据库非常大(大约20-30 MB)当我尝试以这种方式发送超时错误。

我试图将数据库放在公司服务器上,然后将其下载到一个NSData对象中。 然后,我将该数据对象保存到我的应用程序的Documents目录中。 当我重新启动我的应用程序,我得到一个错误,说:“path文件似乎不是一个SQLite数据库”。 代码如下。

 // Download data NSURL *url = [NSURL URLWithString:@"http://www.mysite.net/download/myDatabase.sqlite"]; NSData *fileData = [[NSData alloc] initWithContentsOfURL:url]; NSLog(@"%@",fileData); // Writes a bunch of 8 character (hex?) strings // Delete old database NSError *error; NSURL *destination = [app applicationDocumentsDirectory]; destination = [destination URLByAppendingPathComponent:@"myDatabase"]; destination = [destination URLByAppendingPathExtension:@"sqlite"]; NSLog(@"destination = %@",destination); [[NSFileManager defaultManager] removeItemAtPath:[destination path] error:&error]; // Save into correct location [fileData writeToURL:destination atomically:YES]; //[NSFileManager defaultManager] createFileAtPath:[destination path] contents:fileData attributes:nil]; // I also tried this, it doesn't work either. 

是否有更新应用程序将使用的大型数据库的标准过程? 我感觉到我想要做的事情是不正确的,有一个完全不同的方式来做到这一点,但我不知道是什么。


更新:我尝试了一些事情来试图find问题,但没有让我离任何更近。 我把我试图从服务器上下载的数据库放到USB驱动器上,然后放到我正在开发的mac上,然后放到模拟器中我的应用程序的Documents文件夹中。 当我通过这种方式传输数据库来运行我的应用程序时,它运行没有任何问题,我可以看到我所有的数据。

相反,我完全从模拟器中删除了我的应用程序,并重新运行它,所以它会从头开始创build我的数据库。 我把这个新build的数据库从我的mac传输到我的服务器上,并带有USB驱动器。 一旦该文件在我的服务器上,我试图在上面的代码块中运行我的“下载更新”,但它仍然崩溃下一次我启动我的应用程序与“path文件似乎不是一个SQLite数据库”错误信息。

从这些testing中,我确信问题不在于我正在尝试下载的数据库。 我的“下载更新”代码中的某些内容正在破坏数据库,但我仍然无法弄清楚为什么,也没有find一种可接受的备用方法,一旦我的应用程序启动,即可将我的更新发送给我的用户。


更新2:我一直在做更多的search,并且我已经了解到,用户将需要input用户名和密码来访问我的服务器上的任何文件。 我现在认为,我从上面的代码中得到的NSData实际上是一个身份validation的挑战,或者与之相关的东西,这就是为什么当我用NSFileManager保存它时,它不被识别为sqlite数据库。

我发现通过身份validation最简单的解决scheme是在这里 。 当我尝试做NSData *fileData = [NSData dataWithContentsOfURL:url options:NSDataReadingMapped error:&error]; (改变我的链接后,当然build议链接),我得到一个错误NSCocoaErrorDomain Code=256 ,这只是未知的错误。 这样做后我的fileDatanil 。 我注意到这个post是相当老的,所以我不知道它是否仍然支持。

我还使用NSURLConnection而不是dataWithContentsOfURL发现了一个不同的解决scheme。 这是最近的,但是在那个例子中使用了一些更先进的语法,我从来没有见过。 我几乎可以从示例中复制粘贴,并且我的项目将生成没有错误,但我不知道从我的UIViewController使用fetchURL:withCompletion:failure:例程的正确的语法。 我试过了

 NSError *error; NSData *fileData; ExampleDelegate *download = [[ExampleDelegate alloc] init]; [download fetchURL:url withCompletion:fileData failure:&error]; 

但是这给发送一个不兼容的指针的构build错误。 我想我不能像ExampleDelegateSuccessExampleDelegateFailure对象那样分别传递一个直接的NSDataNSError ,尽pipe它们是从typedef 。 我可能不得不做一些事情来fileDataerror来转换它们,但typedef ing是我所指的上述“先进的语法”之一,我真的不知道该怎么做。

这不包括在他的例子中,但我发现另一个NSURLConnectionDelegate方法称为connection:didReceiveAuthenticationChallenge: 在这里 ,我认为我可以只添加到示例的代码,这应该解决我的身份validation问题。 我觉得如果我只是知道如何调用fetchURL我会被设置。 有没有人有什么我需要做的,以获得fileDataerror到这个调用的意见?

我认为你的问题源于需要与你的服务器进行身份validation。

我推荐stream行的AFNetworking库来帮助进行HTTP调用。 您将会AFHTTPClient ,以提供您的validation细节,就像在这个答案中一样 。

然后在你的情况下,你可以使用AFXMLRequestOperation直接下载你的XML。 然后你可以把它写入磁盘。 请注意,您需要阅读“ iOS数据存储指南”,以查看“文档”文件夹是否适合您的使用(我不认为它是这样;caching可能会更好)。

现在,你的ExampleDelegate代码(看起来像这里来的 )不起作用的原因是ExampleDelegateSuccessExampleDelegateFailure是块types,所以你不能传递你的NSDataNSError *指针。 您需要提供符合相应types签名的块对象。

例如:

 ExampleDelegate *download = [[ExampleDelegate alloc] init]; [download fetchURL:url withCompletion:^(NSData *thedata) { NSLog(@"Success! Data length: %d", theData.length); // Delete old database NSError *error; // You need to declare 'app' here so you can use it in the line below. NSURL *destination = [app applicationDocumentsDirectory]; destination = [destination URLByAppendingPathComponent:@"myDatabase"]; destination = [destination URLByAppendingPathExtension:@"sqlite"]; NSLog(@"destination = %@",destination); [[NSFileManager defaultManager] removeItemAtPath:[destination path] error:&error]; // Save into correct location BOOL success = [fileData writeToURL:destination atomically:YES]; NSLog(@"File written successfully? %d", success); } failure:^(NSError *theError){ NSLog(@"Failure: %@", [theError localizedDescription]} ]; 

块会根据需要为您提供NSDataNSError实例,所以您不需要声明自己的实例。 你可以在这里了解更多关于块。

希望有所帮助:D

我们有大量的数据库,我们经常更新。 我不确定“大”是多大,但我们正在更新兆字节的数据。 我们更新我们的JSON数据。 JSON的开销比XML小一点,而且有很多现成的库(比如JSONKit)。 我们有些用户的数据连接很差,有时会遇到困难。

我们一直在testing不同的更新方式。 一种方法将数据分解为多个JSON文件。 每个文件分别下载,然后分开存储。 使用多个文件的一个优点是,如果一个失败,您只需要重新发送该特定的文件。

另外,我们使用多个线程同时处理多达5个请求/下载。 这需要更多的pipe理,但是可以帮助我们给用户更好的体验。 AFHTTPClient真的很擅长处理这个东西。 我讨厌不使用它。

我最终最终使用AFNetworking来解决我的问题,正如@silver_belt所build议的那样。 我能够做到这一点,但没有AFHTTPClient (见我的答案在这里 ,我作为后续这个问题张贴)。

最后,我不得不在我的视图控制器的.h文件中包含#include "AFHTTPRequestOperation.h" ,然后在.m中使用

 NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"ftp://myUsername:myPassword@www.mysite.net/myfile.sqlite"]]; AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; NSURL *path = [[[app applicationDocumentsDirectory] URLByAppendingPathComponent:@"myfile"] URLByAppendingPathExtension:@"sqlite"]; operation.outputStream = [NSOutputStream outputStreamWithURL:path append:NO]; [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"Successfully downloaded file to path: %@",path); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Error in AFHTTPRequestOperation in clickedButtonAtIndex on FlightInfoController.m"); NSLog(@"%@",error.description); }]; [operation start]; 

当我真的想开始我的下载。 希望这会让那些希望在未来做到这一点的人更容易!

它每次都是一个全新的/独特的数据库,还是同一个数据库的更新版本?

如果是后者,是否考虑过只发送更改(通过添加/更新/删除的明确列表,或使用类似Zumero的自动化更新)?