Storing sqlite databsae in the iphone. Unable to get it back. - iphone

Not sure what the mistake i am doing. Please suggest.
In my application i am creating a database, and when i relaunch the application next time, the database is not seen. I found what the problem is, but not the solution .
NSArray *dirPaths;
NSString *docsDirectory;
NSString *databasePath;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDirectory = [dirPaths objectAtIndex:0];
databasePath = [[NSString alloc] initWithString: [docsDirectory stringByAppendingPathComponent: #"MYDATABASE.db"]];
NSLog (#" Database Path : %# ",databasePath);
const char *dbpath = [databasePath UTF8String];
Unfortunately, i get the following path printed.
Database Path : /var/mobile/Applications/27C4C465-0D65-44AA-BBB3-693G4D1CDD4D/Documents/MYDATABASE.db
When i reinvoke the application i get the different path ie: 27C4C465-0D65-44AA-BBB3-693G4D1CDD4 is replaced with some other value, that's why it could not able to locate the database properly.
How can i resolve this issue? Kindly suggest.

Related

Can we give hardcoded path for sqlite in Xcode?

I'm new to the iPhone development and Mac OS, please bear with the silly query. But I tried hard to get into depth but couldn't found the solution for the problem.
I have created a database in sqlite through command prompt. The database is saved in Users/DNamto/resources.db
But when am trying to open this db in my iPhone application using the following code snippet
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the database file
databasePath = [[NSString alloc]initWithString: [docsDir stringByAppendingPathComponent:#"resources.db"]];
The database fails to open up.
The database path which the application is searching for is :
/Users/DNamto/Library/Application Support/iPhone Simulator/6.0/Applications/C82C3DAF-4E95-49A7-9A4F-4D69B056DC9D/Documents/resources.db
Can anyone help me to get the correct database path.
Can we hard code the DB path so that my application links to it. If yes then please provide the code snippet.
Add your database in the application & check if the db is present in doc directory or not, if not then you need to copy it in doc directory and then access it.
For cppy the db in doc directory use following code snippet
- (void)copyDatabaseIfNeeded {
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
success = [fileManager fileExistsAtPath:[self getDBPath]];
NSString *databasePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"dbname.sqlite"];
if(success)
{
return;// remove old one.
}
[fileManager copyItemAtPath:databasePath toPath:[self getDBPath] error:nil];
}
To open the db use following code snippet
-(void)openDatabase
{
#try
{
[self copyDatabaseIfNeeded];
if(sqlite3_open([[self getDBPath] UTF8String], &mainDatabase)==SQLITE_OK)
{
NSLog(#"Database opened");
}
}
#catch (NSException *exception)
{
NSLog(#"Exception in openDatabase %# :%#",exception.name,exception.reason);
}
}
- (NSString *)getDBPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"dbname.sqlite"];
}
Use following code snippet to close the database.
-(void)closeDatabase:(sqlite3_stmt*)statement
{
#try
{
sqlite3_finalize(statement);
sqlite3_close(mainDatabase);
}
#catch (NSException *exception)
{
NSLog(#"Exception in DatabaseController closeDatabase %# :%#",exception.name,exception.reason);
}
}
You can't. In real device you can't get the hard coded path.
You need a relative path.
Here your issue is your database is not present in the document directory.
You need to add your database to your main bundle and in run time you need to check whether the db is present on document directory, if not you need to copy it to document directory using the NSFileManager.
You can use the following code to copy the database file from bundle to document directory.
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"resource.db"];
NSString *folderPath = [documentsDirectory stringByAppendingPathComponent:#"resource.db"];
NSError *error;
[[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:folderPath error:&error];

Saving NSMutableArray to iPhone device

In the Simulator I can save an NSMutableArray to a file and read it back with the following code:
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:#"RiskValues"]){ // If file exists open into table
NSLog(#"Risk Values File Exists");
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullFileName = [NSString stringWithFormat:#"RiskValues", documentsDirectory];
gRiskValues = [[NSMutableArray alloc] initWithContentsOfFile:fullFileName];
gRiskValuesAlreadyInitialised = YES;
} else {
NSLog(#"Can't find RiskValues file, so initialising gRiskValues table");
Do something else .......
}
This doesn't work on the device. I have tried to locate the file using the following but it still doesn't work:
NSString *fullFileName = [documentsDirectory stringByAppendingPathComponent#"RiskValues"];
What am I doing wrong?
Great answers from everyone. I have resolved the file path and existence issues at a stroke. Many, many thanks.
You have to provide absolute path here:
if ([fileManager fileExistsAtPath:#"RiskValues"])
So it must look like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullFileName = [documentsDirectory stringByAppendingPathComponent:#"RiskValues"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath: fullFileName]){ // If file exists open into table
NSLog(#"Risk Values File Exists");
gRiskValues = [[NSMutableArray alloc] initWithContentsOfFile:fullFileName];
gRiskValuesAlreadyInitialised = YES;
} else {
NSLog(#"Can't find RiskValues file, so initialising gRiskValues table");
Do something else .......
}
NSString *fullFileName = [NSString stringWithFormat:#"RiskValues", documentsDirectory];
this line, you're not creating your full path string right. what you should do is
NSString *fullFileName = [documentsDirectory stringByAppendingPathComponent:#"RiskValues"];
also this check
if ([fileManager fileExistsAtPath:#"RiskValues"])
Will never pass on iOS as it is not a full path to any place you are allowed to write at in your sandbox. I suppose it works on the simulator because on the mac it's looking up relatively to the HD root (or something, not sure how the mac file system works :) ), but on the iOS you're going to have to give it a path to a file/directory in your documents (maybe by appending #"RiskValues" to it or whatever)
1) [NSString stringWithFormat:#"RiskValues", documentsDirectory] is just #"RiskValues". So this name points to file in application's directory.
2) [fileManager fileExistsAtPath:#"RiskValues"] searches for file in application directory. It's available for read/write in simulator (it's in your computer file system after all) but it's read-only on device.
BTW (NSFileManager Class Reference)
Attempting to predicate behavior based
on the current state of the file
system or a particular file on the
file system is not recommended. Doing
so can cause odd behavior in the case
of file system race conditions. It's
far better to attempt an operation
(such as loading a file or creating a
directory), check for errors, and
handle any error gracefully than it is
to try to figure out ahead of time
whether the operation will succeed.
Solution:
1) Do not check file presence. Just try to make dictionary with initWithContentsOfFile:encoding:error:
2) You want it to be in documents directory so construct path like this
[documentsDirectory stringByAppendingPathComponent:#"RiskValues"];

How to load a txt file into an array

I coded a method to load a txt file into an array. However, I'm not really happy with it as it looks terribly cumbersome to my beginner's eyes (I'm sure I don't need 50% of my code) and I am somehow wondering how I can specify the exact format of my txt file, e.g. NSUTF8StringEncoding.
Here is my code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"Sample.txt"];
if (filePath) { // check if file exists - if so load it:
NSString *myText = [NSString stringWithContentsOfFile:filePath];
if (myText) {textView.text=myText;}
}
For any suggestions of how to polish this up and specify the right format, I'd be very grateful.
Try the following, assuming your file is in your bundle:
NSString * filePath = [[NSBundle mainBundle] pathForResource:#"Sample" ofType:#"txt"];
NSError * error = nil;
NSString * contentsOfFile = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
Into an array? You mean into a string, since is exactly what you're doing...
However, your code looks not bad, and most of it is just to grab the documents directory path, and that's not your fault, since it's exactly done this way, according to many knowledge bases.
As of the encoding, stringWithContentsOfFile is deprecated, please use stringWithContentsOfFile:encoding:error: (see the docs)
and you will be able to specify the correct encoding and get accurate error descriptions.

Read/Write to a plist file that comes bundled with the app

I am building an add-on to my app where the user can search for an item in a list that is pre-populated with data from a .plist file. It is an NSDictionary. If the term, the user searched for, does not exist, the user can tap a + button and add it so it is there the next time.
First of I thought it would be as easy as using the NSUserDefaults, but a few problems arises.
To have the list included I must place it in the bundle, but if it is there I can not add new key/value pairs to it. This I can only do with files situated in the Documents folder.
So I guess I have to bundle the plist, then on first run I'll move it to the documents folder and access it there.
This opens up the problem when I need to update the app, I guess it will overwrite the values the user put in.
Is there a secure, easy-understandable, right way to achieve the functionality I describe?
Thanks for any help given:)
Edit: **** the actual approach, as suggested by TheSquad and TomH *****
+ (NSMutableDictionary*) genericProducts {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [documentPaths objectAtIndex:0];
NSString *documentPlistPath = [documentsDirectory stringByAppendingPathComponent:#"GenericProducts.plist"];
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *bundlePlistPath = [bundlePath stringByAppendingPathComponent:#"GenericProducts.plist"];
if([fileManager fileExistsAtPath:documentPlistPath]){
NSMutableDictionary *documentDict = [NSMutableDictionary dictionaryWithContentsOfFile:documentPlistPath];
return documentDict;
} else {
NSError *error;
BOOL success = [fileManager copyItemAtPath:bundlePlistPath toPath:documentPlistPath error:&error];
if (success) {
NSMutableDictionary *newlySavedDict = [NSMutableDictionary dictionaryWithContentsOfFile:documentPlistPath];
return newlySavedDict;
}
return nil;
}
}
And for adding a new product to the list:
+ (void) addItemToGenericProducts:(NSString*) newProduct {
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [documentPaths objectAtIndex:0];
NSString *documentPlistPath = [documentsDirectory stringByAppendingPathComponent:#"GenericProducts.plist"];
NSMutableDictionary *documentDict = [NSMutableDictionary dictionaryWithContentsOfFile:documentPlistPath];
[documentDict setObject:newProduct forKey:[MD5Checksum cheksum:newProduct]];
[documentDict writeToFile:documentPlistPath atomically:YES];
}
I had the same thoughts with my sqlite database...
I end up doing exactly that, copy the bundled file into documents in order to be able to modify it.
What I have done is checking at each startup if the file exist, if it does not, copy it.
If you do an update of your App, the documents folder will not be touch, this means the copied file from the previous version will still be present.
The only issue is that if you want your plist to be upgraded you will have to handle that in your application. If you have to do so I suggest you use the NSUserDefault to check if a previous version of the app existed before...
The contents of the documents directory is not altered when an application is updated.
The contents of the documents directory are deleted when the user deletes the app.
When the app is run the first time write a flag to NSUserDefaults. On subsequent runs of the app, check for existence of the flag. (alternatively, you can just check for existence of the plist in he documents directory)

how to access a folder in documents using iphone

i can access .txt file from documents folder but how to access a folder content lets say documents/A
inside A i have ->a.html, update.cfg
now why i cant access update.cfg??
i am getting null value for zipPath
i tried this but no luck
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *aDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"A"];
NSString *zipPath = [[NSBundle mainBundle] pathForResource:#"update" ofType:#"cfg" inDirectory:aDirectory];
still zipPath=NULL??
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *aDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"A"];
My approach to get to the documentsfolder is a little bit different. (I hope you mean the Documents folder which every application has, not one created by yourself in the mainbundle.^^) I do it like this:
NSString *directoryPath = [[NSHomeDirectory() stringByAppendingPathComponent: #"Documents"] stringByAppendingPathComponent: #"A"];
This is the path to your directory called A in the documents folder. If you know the filename, than you can use another "stringByAppendingPathComponent". ;-) I hope it helps. Else ask again. :-D
after messing up i found this way to acces the file from folder
i got it
NSString *fileName = [NSString stringWithFormat:#"%#/update.cfg",
aDirectory];
NSString *content = [[NSString alloc] initWithContentsOfFile:fileName
usedEncoding:nil
error:nil];
thanks