I need to get some files in definite folders. For this purpose I use this answer and it works fine. However, my folder structure is like:
Documents/
idOfFolder1/
images/
image1.jpg
image2.png
sounds/
sound1.mp3
files/
file1.pdf
idOfFolder2/
images/
...
I need to iterate through all folders having a specific id and get images. Since the answer written iterates through all folders it takes much more time than normal (we have many files). To optimize process, I want to skip "sounds" and "files" folders. Is there a way to handle this?
Thank you!
If you don't like to use NSPredicate, following code will also do what you want,
(this code will directly access the folders with given ids and pick everything inside the images folders)
-(void) printImagesOfFolders:(NSArray *) folderIds{
for(NSString *folderId in folderIds){
NSArray *paths = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSURL *documentsURL = [paths lastObject];
NSString * imageFolderPath = [NSString stringWithFormat:#"%#/images", folderId];
NSURL *rootURL = [documentsURL URLByAppendingPathComponent:imageFolderPath];
NSFileManager *fm = [NSFileManager defaultManager];
NSDirectoryEnumerator *dirEnumerator = [fm enumeratorAtURL:rootURL
includingPropertiesForKeys:#[NSURLNameKey, NSURLIsDirectoryKey]
options:NSDirectoryEnumerationSkipsHiddenFiles
errorHandler:nil];
for (NSURL *url in dirEnumerator) {
NSLog(#"url: %#", url);
}
}
}
How to use it
[self printImagesOfFolders:#[#"idOfFolder1",#"idOfFolder2",#"idOfFolder3",#"idOfFolder4"]];
I think you can implement it in a such different way using a NSPredicate onto the NSDirectoryEnumerator array as in this answer Iterating through files in nested folders or Filter NSFileManager with NSPredicate but the syntax can be awkward: take a look at NSPredicate syntax documentation NSPredicate Format String
In your case I would either:
1. use fast enumeration with a for loop
2. if possible redesign the folder structures
3. use core data or another caching system to speed up the loading process (this involves to sync time to time with the real files)
That's right. The upstairs is right, and the index will be named directly based on the picture so that CPU can find the files accurately
Related
I am working on an iOS library project and need to create an API that takes an NSString parameter which is a path, and the library will write some debugging messages to a file in that path.
I've done some research about logging onto a file in iPhone's file system, one approach is using
freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
This will redirect any following NSLog to a file...
While this seems easy, I have a question: Will this also redirect the API consumer's application(calling application)'s NSLog to the file? I don't want this behavior because I want to be able to control what goes in there as a library..
If that is the behavior, what other approach I can use to achieve my requirement? Thanks.
If I understood correctly, the desired functionality is to pass a path and write some debugging info to a file on that path? If that is so, I don't think you should redirect all your NSLog calls to a file; just using the NSString writeToFile: would be enough:
-(void)writeToFile:(NSString*)path {
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *fileName = [documentsDirectory stringByAppendingPathComponent:path];
NSError *error=nil;
NSString *myMessage="This is the data to write to the file";
[myMessage writeToFile:fileName atomically:YES encoding:NSUTF8StringEncoding error:&error];
}
If you want to append to that file, you can use the NSFileHandle functionality - check the docs here.
Here is the NSURL object that I am using for creating and accessing important configuration file on iOS with features:
hidden from user
not user generated file (storing configuration related to user)
not temp or cache (not possible to create later with existing data)
must be backed up by iCloud/iTunes
[NSURL fileURLWithPath:[[NSSearchPathForDirectoriesInDomains(
NSLibraryDirectory,
NSUserDomainMask,
YES) objectAtIndex:0]
stringByAppendingString:#"/important.txt"]];
As suggested in FileSystemOverview (developer.apple.com), I am storing this file under Library.
Maybe better way is storing it under Library/Application Support.
Using NSSearchPathForDirectoriesInDomains, which takes:
enum NSSearchPathDirectory
NSApplicationDirectory
NSDeveloperApplicationDirectory
NSLibraryDirectory
NSDeveloperDirectory
NSApplicationSupportDirectory
...
enum NSSearchPathDomainMask
NSUserDomainMask
NSLocalDomainMask
NSSystemDomainMask
...
BOOL expandTilde
Is this the correct way of storing such a file?
There are couple of alternatives for NSSearchPathDirectory and NSSearchPathDomainMask.
Also what about the expandTilde, on iOS is it necessary?
Is there a better way of doing it, instead of creating path as a NSString using objectAtIndex and appending file name then converting it to NSURL?
Thanks.
Using NSApplicationSupportDirectory would be my first choice for this.
But keep a few things in mind:
Unlike the "Documents" folder, the "Library/Application Support" folder doesn't exist in an iOS app sandbox by default so you must create the folder before trying to use it.
"Hidden from the user" only means that the user won't see it under normal circumstances. But the file is easily accessible by anyone with any technical knowledge.
You do want to pass YES for the expandTilde parameter so your app returns a proper path when you run the app in the simulator. On a real iOS device, it makes little difference.
Do not use stringByAppendingString: to create paths. Use stringByAppendingPathComponent:.
NSString *appSupportPath = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) firstObject];
NSString *filePath = [appSupportPath stringByAppendingPathComponent:#"important.txt"];
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
You can get a direct NSURL using NSFileManager:
NSURL *appSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] firstObject];
NSURL *fileURL = [appSupportURL URLByAppendingPathComponent:#"important.txt"];
My app uses iTunes File Share. I used the code to delete a single file:
It worked the first time. On the second try, however, iTunes showed a empty share directory. It turns out all data files are gone. Can I recover those data files from the iPad? Thanks
- (void) deleteFileFromDisk: (NSString*) fileName {
if([self fileExists: fileName]) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) ;
NSString *documentsDirectory = [paths objectAtIndex: 0];
NSString* theFile = [documentsDirectory stringByAppendingPathComponent: fileName];
NSError *error;
[[NSFileManager defaultManager] removeItemAtPath: theFile error: &error];
There's no "restore" feature on the iPad. But in all probability there's nothing to worry about.
There's nothing about your code that would delete multiple files. It would delete just that file from the Documents directory that you supplied the name of as fileName. If you didn't call deleteFileFromDisk: multiple times, you didn't delete multiple files.
Perhaps at some point you deleted the app. That would delete its entire sandbox and thus would take with it anything in the Documents directory. That sort of thing is perfectly normal during repeated testing.
I've looked through the Apple documentation on this point and other questions here, but cannot find a means of getting a consistent path to the documents directory.
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *urls = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSURL *directory = [urls lastObject];
This produces a different path each time due to one component.
Example:
file:///var/mobile/Containers/Data/Application/CA708CF5-0E1B-414D-A795-31A8BB884BA5/Documents
Next run:
file:///var/mobile/Containers/Data/Application/2C96E341-85EF-485D-AC19-F8844B0880C3/Documents
I realize I need some kind of relative path here but I cannot figure out how to get it. How can I get to the Documents directory consistently to both write and read a file my app will produce?
The path is determined on installation. Each time you run your app in the simulator, it will be removed and reinstalled. Hence the differernt path. So you don't need to worry about this.
I'm having a problem with the code I'm writing.
I'm writing an iOS program (I'm an iOS rookie) which basically requires me to use quick look framework to view some documents on the iPhone (*.doc, *.ppt, *.pdf etc..) which are stored in the database (Core Data - SQLite, nothing external). I need to add the files somehow, but since iOS isn't really allowing me to browse through its file system I can't find and save the documents i need in database. Which kinda blocks everything else i need to do until I can get those documents from the database. (to set up table views that list the files and the details about the files etc.)
This is for a class project so it doesn't need to be perfect condition, I just need to be able to browse through a few documents while I'm presenting the project. I can add all the documents I'm going to use at one time while I'm coding and I won't need to be able to add any new files when I'm using the program during the presentation. And I don't want it to make it more complicated if i don't have to. Like connecting to an external database with the files already saved in and use a php buffer-page to connect to that database or anything like that. I don't have the necessary server system to execute that php file. I want this operation to be done inside the phone.
The solutions I was able to think of so far:
Grab some random office files from the internet and save them into the database. Then use them later.
Create image scans of some office files and "cheat" by using the scanned image instead of actual documents.
I would really appreciate it if someone can tell me another and much easier way to handle this. Please just keep in mind that while I have a programming background with Java and C#, I'm still an iOS rookie and just barely moving on from scratching the surface. So it is likely that I don't know about something iOS provides by default and I'm just pulling my hair out for nothing.
I think thats it, I hope I didn't forget anything. If you need more details I'm going to be here and I can provide them almost instantly. Thanks everyone in advance for your help.
It sounds like NSFileManager will help you.
If you place your documents into your project tree, they will be available to your app. Use NSFileManager to copy them into the app's Documents folder using something like:
- (void)placeBundleFileInDocuments:(NSString *)filename
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:[[filename lastPathComponent] stringByDeletingPathExtension] ofType:[filename pathExtension]];
NSString *documentsFolderPath = [NSString stringWithFormat:#"%#/", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
NSString *path = [documentsFolderPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#", filename]];
if ([fileManager fileExistsAtPath:path])
return;
NSError *error = nil;
[fileManager copyItemAtPath:bundlePath toPath:path error:&error];
if (error) {
NSLog(#"Unable to copy file (%#).", error.localizedDescription);
}
}
Then, you can use NSFileManager to retrieve details about the files. You might find this method useful:
- (NSDictionary *)attributesOfItemAtPath:(NSString *)path error:(NSError **)error
I hope this helps!