【问题标题】:Getting a list of files in a directory with a glob使用 glob 获取目录中的文件列表
【发布时间】:2010-10-04 17:19:00
【问题描述】:

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

我目前遇到以下问题:

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

..然后去掉我不想要的东西,这很糟糕。但我真正想要的是能够搜索“foo*.jpg”之类的东西,而不是要求整个目录,但我一直找不到类似的东西。

那么你是怎么做到的呢?

【问题讨论】:

标签: ios objective-c iphone cocoa cocoa-touch


【解决方案1】:

您可以在 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];

【讨论】:

  • directoryContentsAtPath 自 iOS 2.0 起已弃用。这个问题+答案太老了……
  • 刚刚更新了代码示例以使用 contentsOfDirectoryAtPath:error: 而不是 directoryContentsAtPath:
  • 是的,您可以使用 OR 语句添加其他逻辑,例如“自我 ENDSWITH '.jpg' 或自我 ENDSWITH '.png'”
  • 这太棒了...我已经用其他方法一整天了!伟大的。主要技巧就是知道要在 StackO 上搜索什么!
  • 您可以使用“pathExtension == '.xxx'”代替“ENDSWITH”。看这个answer
【解决方案2】:

这对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);            
    }       
}

【讨论】:

    【解决方案3】:

    使用 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,因为它是deprecated,因为iOS 2.0
    • 这是列表中第一个回答问题的回复,所以我投了赞成票
    【解决方案4】:

    最简单的方法:

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

    【讨论】:

      【解决方案5】:

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

      下面是一个示例,说明如何将匹配通配模式的文件填充到数组中。使用 glob 函数时,您需要记住一些事项。

      1. 默认情况下,glob 函数在当前工作目录中查找文件。为了搜索另一个目录,您需要将目录名称添加到 globbing 模式中,就像我在示例中所做的那样,以获取 /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 上创建了一个 gist,其中包含名为 NSArray+Globbing 的类别中的上述代码。

      【讨论】:

      • stringWithCString: 已弃用。正确的替换是-[NSFileManager stringWithFileSystemRepresentation:length:],虽然我认为大多数人使用stringWithUTF8String:(这更容易但不能保证是正确的编码)。
      【解决方案6】:

      你需要滚动你自己的方法来消除你不想要的文件。

      使用内置工具这并不容易,但您可以使用RegExKit Lite 来帮助在返回的数组中查找您感兴趣的元素。根据发行说明,这应该适用于 Cocoa 和 Cocoa-触控应用。

      这是我在大约 10 分钟内编写的演示代码。我将 更改为 " 因为它们没有出现在 pre 块内,但它仍然适用于引号。也许对 StackOverflow 上的格式化代码了解更多的人会纠正这个问题(克里斯?)。

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

      #import "基础/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; } @implementation MTFileMatcher - (void)getFilesMatchingRegEx:(NSString*)inRegex forPath:(NSString*)inPath; { NSArray* filesAtPath = [[[NSFileManager defaultManager] directoryContentsAtPath:inPath] arrayByMatchingObjectsWithRegex:inRegex]; NSEnumerator* itr = [filesAtPath objectEnumerator]; NSString* 对象; 而(obj = [itr nextObject]) { NSLog(obj); } } @结尾

      【讨论】:

        【解决方案7】:

        我不会假装是该主题的专家,但您应该可以访问 Objective-c 中的 globwordexp 函数,不是吗?

        【讨论】:

          【解决方案8】:

          stringWithFileSystemRepresentation 在 iOS 中似乎不可用。

          【讨论】:

            【解决方案9】:

            斯威夫特 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)")
                        }
                    }
            

            【讨论】:

              【解决方案10】:

              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  {  }
                      }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2016-02-18
                • 1970-01-01
                • 2016-10-05
                • 1970-01-01
                • 1970-01-01
                • 2017-08-03
                • 2020-02-27
                相关资源
                最近更新 更多