I use the below to create folder in document directory , my question is , how to make this folder hidden , such that when I allow itune share this folder not appear to the user
/* Create new directory */
NSFileManager *filemgr;
NSArray *dirPaths;
NSString *docsDir;
NSString *newDir;
filemgr =[NSFileManager defaultManager];
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
newDir = [docsDir stringByAppendingPathComponent:#"Patients"];
NSLog(newDir);
if(! [self SearchForDirectory:newDir] )
{
NSLog(#"directory Not Exists");
if ([filemgr createDirectoryAtPath:newDir withIntermediateDirectories:YES attributes:nil error: NULL] == NO)
{
NSLog(#"Failed to create directory");
}
}
else{
NSLog(#"directory Exists");
}
[filemgr release];
You can make a folder hidden from iTunes file sharing by prepending the folder name with a dot (.). So the path would be Documents/MyHiddenFolder would be called Documents/.MyHiddenFolder
However, it is now recommended that private data files should be stored in the Library directory, or within a sub-directory of it. Please see the following Apple Q&A for more information.
The Documents directory is for the user's documents. If you're trying to hide files from there, chances are they aren't documents and you should be storing the files in one of the other directories. What files are we talking about?
Note that including non-documents in that directory with iTunes file sharing enables is grounds for rejection from the App Store.
Related
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! :)
In my application I am using the following code to save images/files into the application’s document directory:
-(void)saveImageDetailsToAppBundle{
NSData *imageData = UIImagePNGRepresentation(userSavedImage); //convert image into .png format.
NSFileManager *fileManager = [NSFileManager defaultManager];//create instance of NSFileManager
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //create an array and store result of our search for the documents directory in it
NSString *documentsDirectory = [paths objectAtIndex:0]; //create NSString object, that holds our exact path to the documents directory
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png",txtImageName.text]]; //add our image to the path
NSLog(fullPath);
[fileManager createFileAtPath:fullPath contents:imageData attributes:nil]; //finally save the image
NSLog(#"image saved");
}
However, there is a problem with the image name. If a file exists in the documents directory, the new file with the same name will overwrite the old file. How can I check if the file name exists in the documents directory?
Use NSFileManager's fileExistsAtPath: method to check if it exists or not.
usage
if ( ![fileManager fileExistsAtPath:filePath] ) {
/* File doesn't exist. Save the image at the path */
[fileManager createFileAtPath:fullPath contents:imageData attributes:nil];
} else {
/* File exists at path. Resolve and save */
}
if ([[NSFileManager defaultManager] fileExistsAtPath:myFilePath])
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:#"file name"];
if([fileManager fileExistsAtPath:writablePath]){
// file exist
}
else{
// file doesn't exist
}
As Apple Documentation says it is better to perform some action and then handle no file existance than checking if file is existing.
Note: 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 or race conditions. It's far better to attempt an operation (such as loading a file or creating a directory), check for errors, and handle those errors gracefully than it is to try to figure out ahead of time whether the operation will succeed. For more information on file system race conditions, see “Race Conditions and Secure File Operations” in Secure Coding Guide.
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"];
I am supposed to have downloaded a file on the iPad simulator, using an appication.
How can I check that this file is present on the iPad simulator file system ?
Is there some file manager that I can use to check the existence of the file and possibly its contents?
You can find the simulator at
/Username/Library/Application
Support/iPhone Simulator/4.2/
where "4.2" is the SDK version.
Under that folder you find all applications in cryptical subfolders. One of them is yours.
In there you'lss find "Documents" which is your app's personal folder.
Use these methods, you can verify a file is present in the documents directory. I've not tested this exact example but it should work.
Example:
NSString *filePath = [self dataFilePathInDocuments:#"MyFile.txt"];
if([self fileExistsAtPath:filePath]) {
NSLog(#"The file exits at %#", filePath);
} else {
NSLog(#"The doesn't exist at %#", filePath);
}
Code:
- (NSString *)dataFilePathInDocuments:(NSString*)aFilename {
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDirectory = [paths objectAtIndex:0];
return [docDirectory stringByAppendingPathComponent:aFilename];
}
- (BOOL) fileExistsAtPath:(NSString*)aFilepath {
NSFileManager *fm = [NSFileManager defaultManager];
return [fm fileExistsAtPath:aFilepath];
}
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)