How to get the directory tree of iPhone App Documents Directory - iphone

In my App, I created subfolders under Documents, and subfolders under subfolders. So there is a Document tree. I want to get the tree in a way that I am able to list them in a tableview. They will look like the following, linear listing with different indent to show their level.
I am not sure whether there is some convenient way to get this done or not, when I am trying to do it using while loop and for loop.
Appreciate your suggestions.
Thanks.

Apple provides a number of classes for file system access, and even some for recursion that you're trying to do.
I suggest that you take a look at the Apple File System Programming Guide and the NSFileManager class documentation. Additionally, the NSDirectoryEnumerator class may help as well.

I do not know how to get entire hierarchy at a time. But following method can be helpful.
1 Use this to get documents derectory.
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [paths objectAtIndex:0];
2 use - (NSArray *)contentsOfDirectoryAtPath:(NSString )path error:(NSError *)error for getting list of directories in document directory.
Read this Class refrence for more details.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/Reference/Reference.html
3 Using following method you can make path of internal directory.
NSString *directoryPath = [documentPath stringByAppendingPathComponent:[MAIN_DIRECTORY stringByAppendingPathComponent:filePath]];
Using above three can together you can brows content of document directory.
Hope this is helpful

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
and
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList = [manager directoryContentsAtPath:documentsDirectory];
for (NSString *s in fileList){
NSLog(s);
}

Related

Remove file - Read only file from device

I create a file with attribute NSFileappendonly, i am thinking this is enough to create readonly file in ios.My problem is try to remove the file from device it returns error.Please anyone help me..
A 513 states you do not have permission to write to that folder NSFileWriteNoPermissionError. You need to make sure you are only trying to write to one of the 3 folders in your app's dir (Documents, Temp, or Cache). Generally you use the Documents folder. (Trying to write directly to the main bundle can cause the error you are having)
iOS Environment
You can remove a file with NSFileManager but only if your app is signed and you are attempting to remove from one of the 3 allowed folders. Those 3 folders are only accessible by your app.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [paths objectAtIndex:0];
NSString *yourFile = [documentsDirectoryPath stringByAppendingPathComponent:#"yourFile.txt"];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:yourFile error:NULL];

About NSSearchPathForDirectoriesInDomains

I hv spent quite a while but no luck on following question:
I tried to access Document directory.
Both following codes work perfectly. Could someone tell me whats the difference between
last object and objectAtIndex:0
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [searchPaths lastObject];
or
NSString *documentPath = [searchPaths objectAtIndex:0];
The most close question was How to get URL for application's document directory iPhone, but it didn't explain the difference between lastObject and objectAtIndex:0.
I have read thru Apple Developer Library. It only says 'The directory returned by this method may not exist. This method simply gives you the appropriate location for the requested directory. Depending on the application’s needs, it may be up to the developer to create the appropriate directory and any in between.' Someone please help, thx.
In this case, there is no difference between [searchPaths lastObject] and [searchPaths objectAtIndex:0], because searchPaths contains only one entry. The user domain only contains one document directory.
If you try this you'll get different results:
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(
NSApplicationDirectory, NSAllDomainsMask, YES);
searchPaths may contain more than one directory if you look with NSAllDomainsMask.
Since Xcode 5, best practice is:
NSString *documentPath = [searchPaths firstObject];

iPhone pathForResource vs bundlePath

I want to use pathForResource, but it doesn't look like it will create the path if one doesn't exist. Therefore I'm trying to create one manually by doing the following:
NSString *path = [NSString stringWithFormat:#"%#/%#.plist",[[NSBundle mainBundle] bundlePath],#"myFileName"];
I'm creating files dynamically, so I need to access them after I have Build and Run the application. But it puts the project in a unique id folder so the path comes out to something like:
/Users/RyanJM/Library/Application Support/iPhone Simulator/3.0/Applications/80986747-37FD-49F3-9BA8-41A42AF7A4CB/MyApp.app/myFileName.plist
But that unique id changes every time I do a build. What is the proper way to create a path that I can get to every time (even in the Simulator)?
Thanks.
Update: edited the question, hopefully to help anyone who comes across it in the future.
Update: IWasRobbed answered the proper way to get create a path URL. But the the best answer I've been able to find is from Brad Parks. Though, I do wish there was a cleaner way.
With the way you phrased your question, this is how you read a plist that has been included in the bundle before build:
NSString *propertyListPath = [[NSBundle mainBundle] pathForResource:SomeString ofType:#"plist"];
If you want to access the directories that each app has as a unique storage area for a file that you create AFTER build, you use this:
#define kFilename #”data.plist”
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];
}
Then you can check for it and do some data handling here:
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
// do something with data here
}
You would save yourself a lot of trouble if you bought/read Beginning iPhone 3 Development specifically chapter 11 where he goes over data persistence (which is where this example came from). It's a great book.

How can I get a writable path on the iPhone?

I am posting this question because I had a complete answer for this written out for another post, when I found it did not apply to the original but I thought was too useful to waste. Thus I have also made this a community wiki, so that others may flesh out question and answer(s). If you find the answer useful, please vote up the question - being a community wiki I should not get points for this voting but it will help others find it
How can I get a path into which file writes are allowed on the iPhone? You can (misleadingly) write anywhere you like on the Simulator, but on the iPhone you are only allowed to write into specific locations.
There are three kinds of writable paths to consider - the first is Documents, where you store things you want to keep and make available to the user through iTunes (as of 3.2):
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
Secondly, and very similar to the Documents directory, there is the Library folder, where you store configuration files and writable databases that you also want to keep around, but you don't want the user to be able to mess with through iTunes:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libraryDirectory = [paths objectAtIndex:0];
Note that even though the user cannot see files in iTunes using a device older than 3.2 (the iPad), the NSLibraryDirectory constant has been available since iPhoneOS 2.0, and so can be used for builds targeting 3.0 (or even earlier if you are still doing that). Also the user will not be able to see anything unless you flag an app as allowing users to modify documents, so if you are using Documents today you are fine as long as you change location when updating for support of user documents.
Last there is a cache directory, where you can put images that you don't care exist for the long term or not (the phone may delete them at some point):
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [paths objectAtIndex:0];
BOOL isDir = NO;
NSError *error;
if (! [[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&isDir] && isDir == NO) {
[[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:NO attributes:nil error:&error];
}
Note that you have to actually create the Caches directory there, so when writing you have to check and create every time! Kind of a pain, but that's how it is.
Then when you have a writable path, you just append a file name onto it like so:
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"SomeDirectory/SomeFile.txt"];
or
NSString *filePath = [cachePath stringByAppendingPathComponent:#"SomeTmpFile.png"];
Use that path for reading or writing.
Note that you can make subdirectories in either of those writable paths, which one of the example string above is using (assuming one has been created).
If you are trying to write an image into the photo library, you cannot use file system calls to do this - instead, you have to have a UIImage in memory, and use the UIImageWriteToSavedPhotosAlbum() function call defined by UIKit. You have no control over the destination format or compression levels, and cannot attach any EXIF in this way.
Thanks to Kendall & Dave, above, and I thought this amendment was useful to bring up. When using for one-off debug code, I used this trick from Mike Ash's NSBlog to eliminate the temporary variables isDir & error, minimizing the number of lines and making the verbosity almost bearable:
NSFileHandle *dumpFileHandle = nil;
#ifdef DEBUG
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
if (![[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&(BOOL){0}])
[[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:YES attributes:nil error:&(NSError*){nil}];
NSString *dumpPath = [cachePath stringByAppendingPathComponent:#"dump.txt"];
[[NSFileManager defaultManager] createFileAtPath:dumpPath contents:nil attributes:nil];
[(dumpFileHandle = [NSFileHandle fileHandleForWritingAtPath:dumpPath]) truncateFileAtOffset:0];
#endif
if (dumpFileHandle) [dumpFileHandle writeData:blah];

NSDictionary WriteToFile fails

I can't work out why it keeps failing. It returns NO. I have searched this all afternoon, but nothing explains why or how to fix. Calling [[NSFileManager defaultManager] isWritableFileAtPath:] returns NO, which leads me to believe that the existing plist file can not be overwritten, but I can't work out how to change this.
You can write ONLY files in Documents directory. But your plist file is not there
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];