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
Related
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.
How do I copy the plist in nsdefault in iOS 5
Here is my code:
NSError *error = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *myPlistPath = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat: #"%#.plist", #"Bookmark"] ];
// If it's not there, copy it from the bundle
NSFileManager *fileManager = [NSFileManager defaultManager];
if ( ![fileManager fileExistsAtPath:myPlistPath] ) {
NSString *pathToSettingsInBundle = [[NSBundle mainBundle]
pathForResource:#"Bookmark" ofType:#"plist"];
[fileManager copyItemAtPath:pathToSettingsInBundle toPath:myPlistPath error:&error];
}
[myPlistPath retain];
[myPlistPath release];
It runs in simulator correctly, but on the device it crashes.
Firstly, NSDefault is not a thing, the code provided does not even use NSUserDefaults if thats what you meant,
Now the lines:
[myPlistPath retain];
[myPlistPath release];
are completely redundant, get rid of them.
Now use some common sense when debugging.
cmd-shift-y bring up the console, see what it says.
check that Bookmark.plist exists on the bundle, check if it exists in the documents directory. Check both the simulator and the device.
where does the execution crash?
set some logs e.g. if (error) NSLog(#"Error:%#",error); Log the paths that are generated.
does if ( ![fileManager fileExistsAtPath:myPlistPath] ) evaluate to true or false. set up another log.
profile the run using the zombies tool.
Do a bit more work first next time you are stuck.
I have an app that is supposed to save to a file and later on load it. Now, I have not had ANY problems what so ever on ios 4, so this is perplexing. This has happened on all my apps saving and loading.
Heres the code:
- (NSString *)pathOfFile{
NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsFolder = [paths objectAtIndex:0];
return [documentsFolder stringByAppendingFormat:#"awesome.plist"];
}
Later in in the app...
[array writeToFile:[self pathOfFile] atomically:YES];
And then when I attempt to load it...
if ([[NSFileManager defaultManager] fileExistsAtPath:[self pathOfFile]]) {
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:filepath];
achi.text = [array objectAtIndex:0];
}
My app actually just skips over the if statement (Meaning that it can't find the file I think).
Please help, and if you have different methods of saving files, I would be glad to hear to hear them.
Your - (NSString *)pathOfFile method is wrong. It should be:
- (NSString *)pathOfFile
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsFolder = [paths objectAtIndex:0];
return [documentsFolder stringByAppendingPathComponent:#"awesome.plist"];
}
In your -(NSString *)pathOfFile method, don't use stringByAppendingFormat:. When working with file paths, you should instead use stringByAppendingPathComponent:, as it will ensure that the appropriate slash characters are added (or removed, if there are too many):
return [documentsFolder stringByAppendingPathComponent:#"awesome.plist"];
The comment to my question was what solved the problem, but as I can't give him the correct answer, I'll just write paste his answer here:
Did you make sure the directory is there? Sometimes that Documents directory must be created.
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"];
NSString *myfile = [[NSBundle] mainBundle] pathForResource:#"fileName" ofType:#"plist"];
NSMutableArray *mydata= [[NSMutableArray alloc] initWithContentsOfFile:myfile];
/* code to modify mydata */
[mydata writeToFile:myfile atomically:YES]
In case of simulator 'fileName.plist' is modified but in case of iphone device file remains unchanged. There is no exception seen either.
Is the above code expected to work fine on both iphone and simulator ?
Also in the debugger when I hover over 'mydata' I see different values in case of simulator and device. In case of simulator I see for example, '5 objects' but in case of actual device it shows '{(int)[$VAR count]}'. Could this be related to file not being written ?
You can't write to files in a bundle's resource directory. On top of that you wouldn't want to, because any changes would be overwritten when you update your app. The documents directory persists across versions and (I believe) it is backed up via itunes.
Here is a snippet that checks the documents directory for a plist. if the file doesn't exist it copies a plist out of the resources into the documents directory.
BOOL success;
NSFileManager* fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"score.plist"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) return success;
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"score.plist"]];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
return success;