In my app, I would like to recognize when the database has been damaged and automatically repair it. Specifically, when the app is first opened I run an ANALYZE command and if it comes back with status 11 (database disk image is malformed), then I would like to have a way of recovering the data.
All the examples I find use the terminal to do a dump and then import of the subsequent SQL command file.
How can I do a dump of the db from within my own code since the command line isn't available on iOS?
Thanks
I think you can easily copy and save the database with another name (extend timestamp). You have to figure out when it is damaging(It should not damage it depends on your meaning of damage) and replace it.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *sqlpath = [documentsDirectory stringByAppendingPathComponent:#"Your-sqlitefile"];
NSString *sqldump = //append timestamp
[fileManager copyItemAtPath:sqlpath toPath:sqldump error:&error];
Edit:
Please refer below answer. I have not used by myself but hope it helps.
https://stackoverflow.com/a/27453637/1881472
Related
My app uses iTunes File Share. I used the code to delete a single file:
It worked the first time. On the second try, however, iTunes showed a empty share directory. It turns out all data files are gone. Can I recover those data files from the iPad? Thanks
- (void) deleteFileFromDisk: (NSString*) fileName {
if([self fileExists: fileName]) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) ;
NSString *documentsDirectory = [paths objectAtIndex: 0];
NSString* theFile = [documentsDirectory stringByAppendingPathComponent: fileName];
NSError *error;
[[NSFileManager defaultManager] removeItemAtPath: theFile error: &error];
There's no "restore" feature on the iPad. But in all probability there's nothing to worry about.
There's nothing about your code that would delete multiple files. It would delete just that file from the Documents directory that you supplied the name of as fileName. If you didn't call deleteFileFromDisk: multiple times, you didn't delete multiple files.
Perhaps at some point you deleted the app. That would delete its entire sandbox and thus would take with it anything in the Documents directory. That sort of thing is perfectly normal during repeated testing.
I'm using this code to read data from a local (in the XCode project) .plist file.
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"GameData.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"GameData" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath: path error:&error];
}
gameData = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
And it worked great the start, but now I find when I step through the code in the simulator that my game is using a version of the .plist file that existed right at the start, and the new fields I've set up in my new GameData.plist file is not appearing.
I presume that's because it doesn't get the data again if the file already exists? but then how do I get the new version of the .plist file? I tried removing the if statement, but I get a runtime error saying the file already exists.
It sounds like you need to setup a version system. But, the only reason to copy a file from the bundle to the documents folder is so you can edit it, so you need to think about how to merge the updated file in the bundle and the users additions in the documents folder.
Once you have a plan for merging the files, then you can change your if statement so it doesn't just check if the file already exists (if it does, you need to delete it before you can replace it) but also considers the version. You may want to store the currently copied version number in user defaults and add a version number to the file in the bundle. You may also want to keep the user modified data in a different file and use that as overrides.
I'd like to create a routine for the user to save their current version of my app's sqlite database into an app-specific folder in NSDocumentsDirectory, and then to generate a file list of saved sql files and load one of the file list (including the default file) as the working sql version. I'm reasonably familiar with core data, but this is my first foray into file archiving and retrieval. I've seen topics which cover saving NSData, but not Core Data SQL files. How do I do it?
Marcin - thanks. So if I have a UITextfield called fninput, is it like this?
NSString *path;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); path = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"inControl"];
NSString *filename = [fninput.text stringByAppendingString:#".sql"];
path = [path stringByAppendingPathComponent:filename];
[[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil];
I want to distribute a populated database with my app. I am trying to implement the SQLitePlugin, but as the page says there is not any documentation for how to do it on iOS. I tried to implement this outdated steps but without any luck. Is there anyone who did this?
I found a solution at least it works for me so here is :
I used and followed the tutorial in the link you mentioned : http://gauravstomar.blogspot.fr/2011/08/prepopulate-sqlite-in-phonegap.html
Be sure to copy and past the good database.db and 000...001.db (the good one are either in /Caches and /Caches/file_0 folders or in /WebKit and /WebKit/file__0, i don't remember so try one then the other if it doesn't work). then i pasted them in my resources' project directory.
I modify the two lines :
NSString *masterPath = [libraryDir stringByAppendingPathComponent:#"WebKit/Databases/"];
NSString *databasePath = [libraryDir stringByAppendingPathComponent:#"WebKit/Databases/file__0/"];
by the following lines :
NSString *masterPath = [libraryDir stringByAppendingPathComponent:#"Caches/"];
NSString *databasePath = [libraryDir stringByAppendingPathComponent:#"Caches/file__0/"];
Remove your application from your simulator/device. And then run.. it works, my database is pre-populated.
I put the database in the Resources folder and placed this code in MainViewController.m.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *databasePath = [documentsDirectory stringByAppendingPathComponent:#"this.db"];
if ([fileManager fileExistsAtPath:databasePath] == NO) {
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"this" ofType:#"db"];
[fileManager copyItemAtPath:resourcePath toPath:databasePath error:&error];
}
The following comes from a blog post - but as I've been slightly spanked for posting links before I'm going to quote from it. I'll post the URL at the end though and I recommend you go there for a full explanation and some follow up comments. This help comes credit Scott Buckel.
1) Use this plugin: https://github.com/chbrody/Cordova-SQLitePlugin/
2) Copy your sqlite db file to /assets folder of PhoneGap.
3) Then, follow instructions here: http://gauravstomar.blogspot.com/2011/08/prepopulate-sqlite-in-phonegap.html to copy the file to native storage. Change this.copy("Databases.db","/data/data/"+pName+"/app_database/");
3a) Instead of Databases.db, use your database filename.
3b) Instead of app_database, use "databases"
3c) You'll probably want to delete the file from /assets, since it is duplicated and no longer needed. My app was double the size it needed to be.
4) (Not sure if this step is necessary, I'm getting out of the office for the day). Edit SQLitePlugin.java
4a) Lines 176, I edited 1==1 so that if statement is always executed. Line 179 I changed this.setStorage(appPackage, false); to this.setStorage(appPackage, true);
5) You can then use the following command to open the DB and use it as any other PhoneGap database
5a) var db = window.sqlitePlugin.openDatabase("[full_database_name_including_extension]", "1.0", "PhoneGap Demo", 200000);
Full blog post: http://www.raymondcamden.com/index.cfm/2012/7/27/Guest-Blog-Post-Shipping-a-populated-SQLite-DB-with-PhoneGap
How to create a file and save it as a text file in iPad through the application?. If I had to read that file at a later stage how to specify the absolute path. Could some one help on this.
Is it possible to display the text file created using the iPad app in the device homescreen, so that user's will be able to modify it.
To Write a file to documents directory use following code, (you may need to do some syntax correction as not tested)
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir =[documentPaths objectAtIndex:0];
NSString *filePath = [documentsDir stringByAppendingPathComponent:yourFileName];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager createFileAtPath:filePath contents:nil attributes:nil];
// Open a handle to it.
NSFileHandle* pfile = [NSFileHandle fileHandleForWritingAtPath:filePath];
[pfile writeData:[[NSString stringWithString:#"YourData"] dataUsingEncoding:NSUTF8StringEncoding]];
And to provide user facility to edit it you can use, one option I can see.
Enable "Application supports iTunes file sharing"in plist file of the application so that user would be able to see the documents through the itunes.
You need to read and check the content though to track the changes done to document.