Obj-C, how do I copy a file with NSSearchPathForDirectoriesInDomains? - iphone

I want to copy some files as part of a backup routine.
I have the following function which gives the location of my files.
- (NSString *)getLocalDocumentPath:(NSString*)strFile {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0]
stringByAppendingPathComponent:strFile];
return path;
}
Heres my database
NSString *filePath = [self getLocalDocumentPath:#"mydatabase.db"];
I want to copy this to a new file called upload.txt
NSString *filePath = [self getLocalDocumentPath:#"upload.txt"];
Then later on I download a file.
NSString *filePath = [self getLocalDocumentPath:#"download.txt"];
Which I want to copy on top of my original database file.
NSString *filePath = [self getLocalDocumentPath:#"mydatabase.db"];

NSFileManager *fileManager = [NSFilemanager defaultManager];
[fileManager copyItemAtPath:databasePath toPath:uploadFilePath error:nil];
and if you want to overwrite the database using the download.txt, make an instance of NSData and use - (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile

Sounds like you want to get to know NSFileManager very well (documentation is linked for you).
The method you'd most likely be most interested in is:
moveItemAtPath:toPath:error:

one method could be:
you can read the file contents you want to save in NSData then can use:
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile
in which you can replace the path with one your relative file paths you have mentioned for various files.

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];

Cannot create a file using stringByAppendingPathComponent

This code has worked up until yesterday in my app:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *applicationDocDirectory = [paths objectAtIndex:0];
NSLog(#"%#", applicationDocDirectory);
NSString *tempFilePath = [applicationDocDirectory stringByAppendingPathComponent:#"temp.txt"];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL success = [fileManager fileExistsAtPath:tempFilePath];
I continue to get Cocoa error code 4, that my file doesn't exist at the path. I checked the path and the path is correct. Is there any obvious reason why this code stopped working? I tried cleaning, deleting my app from the simulator or the device and that fixed it for awhile, but then it just stopped working. Not really sure what else is going in that could be causing this issue. THanks.
You can't create a file by using -stringByAppendingPathComponent. That creates an autoreleased NSString object.
If this has been working then the "temp.txt" must already exist.
To create the file you can use:
- (BOOL)createFileAtPath:(NSString *)path contents:(NSData *)contents attributes:(NSDictionary *)attributes
To create a file from an NSString you can use:
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile encoding:(NSStringEncoding)enc error:(NSError **)error

Copy file to different directory

Let's say I have a file at the path /documents/recording.caf and I want to copy it into the folder /documents/folder. How would I do this? If I want to use the following code, it appears as though I have to include the file name and extension in the path, which I will not always know.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *newPath = [documentsDirectory stringByAppendingPathComponent:#"/temporary/recording.caf"];
if ([fileManager fileExistsAtPath:newPath] == NO) {
[fileManager copyItemAtPath:file toPath:newPath error:&error];
}
}
A tableview is updated with every file it finds in a directory and if the user taps a cell, I want to copy this file somewhere else.
Since the appended path component is also a string, you could use another create another string with the file name that you do not know
NSString *anotherString=[NSString stringWithFormat:#"/temporary/%#",<yourfilenameAsString>];
and just append that to newPath.
I would also suggest that you should not be constructing paths like #"/temporary/filename.extension". But rather, you construct it as using the path construction methods of NSString like
- (NSString *)stringByAppendingPathComponent:(NSString *)aString
- (NSString *)stringByAppendingPathExtension:(NSString *)ext

How to check if folder is empty, and instantiate file names inside the folder into NSStrings? (iphone cocoa)

Just wondering, how would I check if a particular folder is holding files, and instantiate file names inside the folder into NSStrings? I know of a class called NSFileManager, but I'm not sure how to apply it to suit my objective.
NSArray * files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:folderLocationString error:nil];
By default all your custom files and data will be stored in the documents directory in your app. I've put a sample code below to access the default document directory; plus a custom folder you may have in there called 'MyFolderName'
The end result will be an array which has a list of NSString objects of the files or directories in the path you have specified.
//Accessing the default documents directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//Appending the name of your custom folder, if you have any
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"MyFolderName"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:path]) { // Directory exists
NSArray *listOfFiles = [fileManager contentsOfDirectoryAtPath:path error:nil];
}
Hope this helps! :)

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"];