For some crazy reason I can't find a way to get a list of files with a glob for a given directory.
I'm currently stuck with something along the lines of:
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSArray *dirContents = [[NSFileManager defaultManager]
directoryContentsAtPath:bundleRoot];
..and then stripping out the stuff I don't want, which sucks. But what I'd really like is to be able to search for something like "foo*.jpg" instead of asking for the entire directory, but I've not been able to find anything like that.
So how the heck do you do it?
This question is related to
ios
objective-c
iphone
cocoa
cocoa-touch
I won't pretend to be an expert on the topic, but you should have access to both the glob
and wordexp
function from objective-c, no?
You need to roll your own method to eliminate the files you don't want.
This isn't easy with the built in tools, but you could use RegExKit Lite to assist with finding the elements in the returned array you are interested in. According to the release notes this should work in both Cocoa and Cocoa-Touch applications.
Here's the demo code I wrote up in about 10 minutes. I changed the < and > to " because they weren't showing up inside the pre block, but it still works with the quotes. Maybe somebody who knows more about formatting code here on StackOverflow will correct this (Chris?).
This is a "Foundation Tool" Command Line Utility template project. If I get my git daemon up and running on my home server I'll edit this post to add the URL for the project.
#import "Foundation/Foundation.h" #import "RegexKit/RegexKit.h" @interface MTFileMatcher : NSObject { } - (void)getFilesMatchingRegEx:(NSString*)inRegex forPath:(NSString*)inPath; @end int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // insert code here... MTFileMatcher* matcher = [[[MTFileMatcher alloc] init] autorelease]; [matcher getFilesMatchingRegEx:@"^.+\\.[Jj][Pp][Ee]?[Gg]$" forPath:[@"~/Pictures" stringByExpandingTildeInPath]]; [pool drain]; return 0; } @implementation MTFileMatcher - (void)getFilesMatchingRegEx:(NSString*)inRegex forPath:(NSString*)inPath; { NSArray* filesAtPath = [[[NSFileManager defaultManager] directoryContentsAtPath:inPath] arrayByMatchingObjectsWithRegex:inRegex]; NSEnumerator* itr = [filesAtPath objectEnumerator]; NSString* obj; while (obj = [itr nextObject]) { NSLog(obj); } } @end
Unix has a library that can perform file globbing operations for you. The functions and types are declared in a header called glob.h
, so you'll need to #include
it. If open up a terminal an open the man page for glob by typing man 3 glob
you'll get all of the information you need to know to use the functions.
Below is an example of how you could populate an array the files that match a globbing pattern. When using the glob
function there are a few things you need to keep in mind.
glob
function looks for files in the current working directory. In order to search another directory you'll need to prepend the directory name to the globbing pattern as I've done in my example to get all of the files in /bin
.glob
by calling globfree
when you're done with the structure.In my example I use the default options and no error callback. The man page covers all of the options in case there's something in there you want to use. If you're going to use the above code, I'd suggest adding it as a category to NSArray
or something like that.
NSMutableArray* files = [NSMutableArray array];
glob_t gt;
char* pattern = "/bin/*";
if (glob(pattern, 0, NULL, >) == 0) {
int i;
for (i=0; i<gt.gl_matchc; i++) {
[files addObject: [NSString stringWithCString: gt.gl_pathv[i]]];
}
}
globfree(>);
return [NSArray arrayWithArray: files];
Edit: I've created a gist on github that contains the above code in a category called NSArray+Globbing.
Swift 5 for cocoa
// Getting the Contents of a Directory in a Single Batch Operation
let bundleRoot = Bundle.main.bundlePath
let url = URL(string: bundleRoot)
let properties: [URLResourceKey] = [ URLResourceKey.localizedNameKey, URLResourceKey.creationDateKey, URLResourceKey.localizedTypeDescriptionKey]
if let src = url{
do {
let paths = try FileManager.default.contentsOfDirectory(at: src, includingPropertiesForKeys: properties, options: [])
for p in paths {
if p.hasSuffix(".data"){
print("File Path is: \(p)")
}
}
} catch { }
}
You need to roll your own method to eliminate the files you don't want.
This isn't easy with the built in tools, but you could use RegExKit Lite to assist with finding the elements in the returned array you are interested in. According to the release notes this should work in both Cocoa and Cocoa-Touch applications.
Here's the demo code I wrote up in about 10 minutes. I changed the < and > to " because they weren't showing up inside the pre block, but it still works with the quotes. Maybe somebody who knows more about formatting code here on StackOverflow will correct this (Chris?).
This is a "Foundation Tool" Command Line Utility template project. If I get my git daemon up and running on my home server I'll edit this post to add the URL for the project.
#import "Foundation/Foundation.h" #import "RegexKit/RegexKit.h" @interface MTFileMatcher : NSObject { } - (void)getFilesMatchingRegEx:(NSString*)inRegex forPath:(NSString*)inPath; @end int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // insert code here... MTFileMatcher* matcher = [[[MTFileMatcher alloc] init] autorelease]; [matcher getFilesMatchingRegEx:@"^.+\\.[Jj][Pp][Ee]?[Gg]$" forPath:[@"~/Pictures" stringByExpandingTildeInPath]]; [pool drain]; return 0; } @implementation MTFileMatcher - (void)getFilesMatchingRegEx:(NSString*)inRegex forPath:(NSString*)inPath; { NSArray* filesAtPath = [[[NSFileManager defaultManager] directoryContentsAtPath:inPath] arrayByMatchingObjectsWithRegex:inRegex]; NSEnumerator* itr = [filesAtPath objectEnumerator]; NSString* obj; while (obj = [itr nextObject]) { NSLog(obj); } } @end
What about using NSString's hasSuffix and hasPrefix methods? Something like (if you're searching for "foo*.jpg"):
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSArray *dirContents = [[NSFileManager defaultManager] directoryContentsAtPath:bundleRoot];
for (NSString *tString in dirContents) {
if ([tString hasPrefix:@"foo"] && [tString hasSuffix:@".jpg"]) {
// do stuff
}
}
For simple, straightforward matches like that it would be simpler than using a regex library.
I won't pretend to be an expert on the topic, but you should have access to both the glob
and wordexp
function from objective-c, no?
You can achieve this pretty easily with the help of NSPredicate, like so:
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *dirContents = [fm contentsOfDirectoryAtPath:bundleRoot error:nil];
NSPredicate *fltr = [NSPredicate predicateWithFormat:@"self ENDSWITH '.jpg'"];
NSArray *onlyJPGs = [dirContents filteredArrayUsingPredicate:fltr];
If you need to do it with NSURL instead it looks like this:
NSURL *bundleRoot = [[NSBundle mainBundle] bundleURL];
NSArray * dirContents =
[fm contentsOfDirectoryAtURL:bundleRoot
includingPropertiesForKeys:@[]
options:NSDirectoryEnumerationSkipsHiddenFiles
error:nil];
NSPredicate * fltr = [NSPredicate predicateWithFormat:@"pathExtension='jpg'"];
NSArray * onlyJPGs = [dirContents filteredArrayUsingPredicate:fltr];
I won't pretend to be an expert on the topic, but you should have access to both the glob
and wordexp
function from objective-c, no?
Swift 5
This works for cocoa
let bundleRoot = Bundle.main.bundlePath
let manager = FileManager.default
let dirEnum = manager.enumerator(atPath: bundleRoot)
while let filename = dirEnum?.nextObject() as? String {
if filename.hasSuffix(".data"){
print("Files in resource folder: \(filename)")
}
}
I won't pretend to be an expert on the topic, but you should have access to both the glob
and wordexp
function from objective-c, no?
Swift 5 for cocoa
// Getting the Contents of a Directory in a Single Batch Operation
let bundleRoot = Bundle.main.bundlePath
let url = URL(string: bundleRoot)
let properties: [URLResourceKey] = [ URLResourceKey.localizedNameKey, URLResourceKey.creationDateKey, URLResourceKey.localizedTypeDescriptionKey]
if let src = url{
do {
let paths = try FileManager.default.contentsOfDirectory(at: src, includingPropertiesForKeys: properties, options: [])
for p in paths {
if p.hasSuffix(".data"){
print("File Path is: \(p)")
}
}
} catch { }
}
Unix has a library that can perform file globbing operations for you. The functions and types are declared in a header called glob.h
, so you'll need to #include
it. If open up a terminal an open the man page for glob by typing man 3 glob
you'll get all of the information you need to know to use the functions.
Below is an example of how you could populate an array the files that match a globbing pattern. When using the glob
function there are a few things you need to keep in mind.
glob
function looks for files in the current working directory. In order to search another directory you'll need to prepend the directory name to the globbing pattern as I've done in my example to get all of the files in /bin
.glob
by calling globfree
when you're done with the structure.In my example I use the default options and no error callback. The man page covers all of the options in case there's something in there you want to use. If you're going to use the above code, I'd suggest adding it as a category to NSArray
or something like that.
NSMutableArray* files = [NSMutableArray array];
glob_t gt;
char* pattern = "/bin/*";
if (glob(pattern, 0, NULL, >) == 0) {
int i;
for (i=0; i<gt.gl_matchc; i++) {
[files addObject: [NSString stringWithCString: gt.gl_pathv[i]]];
}
}
globfree(>);
return [NSArray arrayWithArray: files];
Edit: I've created a gist on github that contains the above code in a category called NSArray+Globbing.
Very Simplest Method:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList = [manager contentsOfDirectoryAtPath:documentsDirectory
error:nil];
//--- Listing file by name sort
NSLog(@"\n File list %@",fileList);
//---- Sorting files by extension
NSArray *filePathsArray =
[[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory
error:nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF EndsWith '.png'"];
filePathsArray = [filePathsArray filteredArrayUsingPredicate:predicate];
NSLog(@"\n\n Sorted files by extension %@",filePathsArray);
You need to roll your own method to eliminate the files you don't want.
This isn't easy with the built in tools, but you could use RegExKit Lite to assist with finding the elements in the returned array you are interested in. According to the release notes this should work in both Cocoa and Cocoa-Touch applications.
Here's the demo code I wrote up in about 10 minutes. I changed the < and > to " because they weren't showing up inside the pre block, but it still works with the quotes. Maybe somebody who knows more about formatting code here on StackOverflow will correct this (Chris?).
This is a "Foundation Tool" Command Line Utility template project. If I get my git daemon up and running on my home server I'll edit this post to add the URL for the project.
#import "Foundation/Foundation.h" #import "RegexKit/RegexKit.h" @interface MTFileMatcher : NSObject { } - (void)getFilesMatchingRegEx:(NSString*)inRegex forPath:(NSString*)inPath; @end int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // insert code here... MTFileMatcher* matcher = [[[MTFileMatcher alloc] init] autorelease]; [matcher getFilesMatchingRegEx:@"^.+\\.[Jj][Pp][Ee]?[Gg]$" forPath:[@"~/Pictures" stringByExpandingTildeInPath]]; [pool drain]; return 0; } @implementation MTFileMatcher - (void)getFilesMatchingRegEx:(NSString*)inRegex forPath:(NSString*)inPath; { NSArray* filesAtPath = [[[NSFileManager defaultManager] directoryContentsAtPath:inPath] arrayByMatchingObjectsWithRegex:inRegex]; NSEnumerator* itr = [filesAtPath objectEnumerator]; NSString* obj; while (obj = [itr nextObject]) { NSLog(obj); } } @end
Very Simplest Method:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList = [manager contentsOfDirectoryAtPath:documentsDirectory
error:nil];
//--- Listing file by name sort
NSLog(@"\n File list %@",fileList);
//---- Sorting files by extension
NSArray *filePathsArray =
[[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory
error:nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF EndsWith '.png'"];
filePathsArray = [filePathsArray filteredArrayUsingPredicate:predicate];
NSLog(@"\n\n Sorted files by extension %@",filePathsArray);
Swift 5
This works for cocoa
let bundleRoot = Bundle.main.bundlePath
let manager = FileManager.default
let dirEnum = manager.enumerator(atPath: bundleRoot)
while let filename = dirEnum?.nextObject() as? String {
if filename.hasSuffix(".data"){
print("Files in resource folder: \(filename)")
}
}
What about using NSString's hasSuffix and hasPrefix methods? Something like (if you're searching for "foo*.jpg"):
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSArray *dirContents = [[NSFileManager defaultManager] directoryContentsAtPath:bundleRoot];
for (NSString *tString in dirContents) {
if ([tString hasPrefix:@"foo"] && [tString hasSuffix:@".jpg"]) {
// do stuff
}
}
For simple, straightforward matches like that it would be simpler than using a regex library.
This works quite nicely for IOS
, but should also work for cocoa
.
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSFileManager *manager = [NSFileManager defaultManager];
NSDirectoryEnumerator *direnum = [manager enumeratorAtPath:bundleRoot];
NSString *filename;
while ((filename = [direnum nextObject] )) {
//change the suffix to what you are looking for
if ([filename hasSuffix:@".data"]) {
// Do work here
NSLog(@"Files in resource folder: %@", filename);
}
}
stringWithFileSystemRepresentation doesn't appear to be available in iOS.
You can achieve this pretty easily with the help of NSPredicate, like so:
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *dirContents = [fm contentsOfDirectoryAtPath:bundleRoot error:nil];
NSPredicate *fltr = [NSPredicate predicateWithFormat:@"self ENDSWITH '.jpg'"];
NSArray *onlyJPGs = [dirContents filteredArrayUsingPredicate:fltr];
If you need to do it with NSURL instead it looks like this:
NSURL *bundleRoot = [[NSBundle mainBundle] bundleURL];
NSArray * dirContents =
[fm contentsOfDirectoryAtURL:bundleRoot
includingPropertiesForKeys:@[]
options:NSDirectoryEnumerationSkipsHiddenFiles
error:nil];
NSPredicate * fltr = [NSPredicate predicateWithFormat:@"pathExtension='jpg'"];
NSArray * onlyJPGs = [dirContents filteredArrayUsingPredicate:fltr];
This works quite nicely for IOS
, but should also work for cocoa
.
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSFileManager *manager = [NSFileManager defaultManager];
NSDirectoryEnumerator *direnum = [manager enumeratorAtPath:bundleRoot];
NSString *filename;
while ((filename = [direnum nextObject] )) {
//change the suffix to what you are looking for
if ([filename hasSuffix:@".data"]) {
// Do work here
NSLog(@"Files in resource folder: %@", filename);
}
}
Source: Stackoverflow.com