使用glob获取目录中的文件列表


136

出于某种疯狂的原因,我找不到一种方法来获取给定目录的文件列表。

我目前坚持以下方面:

NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSArray *dirContents = [[NSFileManager defaultManager] 
                        directoryContentsAtPath:bundleRoot];

..然后去掉我不想要的东西,这很烂。但是我真正想要的是能够搜索“ foo * .jpg”之类的内容,而不是查询整个目录,但是我却找不到类似的东西。

那么,你怎么做到的呢?


布莱恩·韦伯斯特(Brian Webster)的回答在类似的问题上对我有很大帮助。stackoverflow.com/questions/5105250/…–
Wytchkraft

1
提醒所有阅读此文件的人,您只需将文件放入文件夹stackoverflow.com/questions/1762836/…–
seo

Answers:


240

您可以借助NSPredicate轻松实现此目标,如下所示:

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];

如果您需要使用NSURL代替,它看起来像这样:

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];

2
从iOS 2.0开始不推荐使用directoryContentsAtPath。这个问题+答案太旧了……
Jonny

7
只是继续并更新了代码示例以使用contentsOfDirectoryAtPath:error:而不是directoryContentsAtPath:
Brian Webster

5
是的,您可以使用OR语句添加其他逻辑,例如“ self ENDSWITH'.jpg'或self ENDSWITH'.png'”
Brian Webster

2
太棒了...我整天都在烦恼其他方法!大。主要技巧就是知道在StackO上搜索什么!
Cliff Ribaudo 2012年

3
您可以使用“ pathExtension =='.xxx'”代替“ ENDSWITH”。看这个答案
Bruno Berisso 2012年

34

这非常适合IOS,但也应该适用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);            
    }       
}

28

如何使用NSString的hasSuffix和hasPrefix方法?类似于(如果您要搜索“ 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

    }
}

对于像这样的简单明了的匹配,它比使用正则表达式库更简单。


您应该使用contentsOfDirectoryAtPath:error:的,而不是directoryContentsAtPath因为它deprecatediOS2.0
亚历CIO

这是列表中回答该问题的第一个回复,所以我投了赞成票
Guy

12

最简单的方法:

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);

10

Unix有一个可以为您执行文件全局操作的库。函数和类型在称为的标头中声明glob.h,因此您将需要#include它。如果打开终端,请输入以下内容以打开glob的手册页man 3 glob您将获得使用这些功能所需的所有信息。

下面是一个示例,说明如何使用匹配模式填充文件的数组。使用该glob功能时,需要记住一些注意事项。

  1. 默认情况下,该glob函数在当前工作目录中查找文件。为了搜索另一个目录,您需要像在示例中所做的那样在目录名称前添加通配模式,以获取所有文件。/bin
  2. 完成结构后,您负责清理glob通过调用分配的内存globfree

在我的示例中,我使用默认选项,并且没有错误回调。手册页涵盖了所有选项,以防您要使用其中的某些内容。如果您要使用上面的代码,建议您将其作为类别添加到NSArray或类似的内容中。

NSMutableArray* files = [NSMutableArray array];
glob_t gt;
char* pattern = "/bin/*";
if (glob(pattern, 0, NULL, &gt) == 0) {
    int i;
    for (i=0; i<gt.gl_matchc; i++) {
        [files addObject: [NSString stringWithCString: gt.gl_pathv[i]]];
    }
}
globfree(&gt);
return [NSArray arrayWithArray: files];

编辑:我在github上创建了一个要点,该要点包含上述代码,称为NSArray + Globbing


stringWithCString:不推荐使用。正确的替换是-[NSFileManager stringWithFileSystemRepresentation:length:],尽管我认为大多数人都使用stringWithUTF8String:(这比较容易,但不能保证是正确的编码)。
彼得·霍西

5

您需要使用自己的方法来消除不需要的文件。

使用内置工具很难做到这一点,但是您可以使用RegExKit Lite来帮助您找到感兴趣的返回数组中的元素。根据发行说明,这在Cocoa和Cocoa-Touch应用程序中均应适用。

这是我在大约10分钟内编写的演示代码。我将<和>更改为“,因为它们没有出现在pre块内,但仍可以使用引号。也许有人对StackOverflow上的代码格式了解更多的人会纠正此问题(Chris?)。

这是一个“基础工具”命令行实用程序模板项目。如果我在自己的家庭服务器上启动并运行了git守护程序,则将编辑此帖子以添加项目的URL。

#import“ Foundation / Foundation.h”
#import“ RegexKit / RegexKit.h”

@interface MTFileMatcher:NSObject 
{
}
-(void)getFilesMatchingRegEx:(NSString *)inRegex forPath:(NSString *)inPath;
@结束

int main(int argc,const char * argv [])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    //在此处插入代码...
    MTFileMatcher * matcher = [[[[MTFileMatcher alloc] init] autorelease];
    [matcher getFilesMatchingRegEx:@“ ^。+ \\。[Jj] [Pp] [Ee]?[Gg] $” forPath:[@“〜/ Pictures” stringByExpandingTildeInPath]];

    [池排水];
    返回0;
}

@实现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);
    }
}
@结束

3

我不会假装自己是该主题的专家,但您应该可以从Objective-C 进入globwordexp功能。



0

斯威夫特5

这适用于可可

        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)")
            }
        }

0

Swift 5可可

        // 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  {  }
        }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.