2011-04-21 117 views
38

我需要访问文件夹中的每个文件,包括嵌套文件夹中存在的文件。示例文件夹可能如下所示。使用嵌套文件夹遍历文件夹中的文件 - Cocoa

animals/ 
-k.txt 
-d.jpg 
cat/ 
    -r.txt 
    -z.jpg 
    tiger/ 
     -a.jpg 
     -p.pdf 
dog/ 
    -n.txt 
    -f.jpg 
-p.pdf 

假设我想对“动物”中不是文件夹的每个文件运行一个进程。迭代文件夹“动物”及其所有子文件夹以访问每个文件的最佳方法是什么?

谢谢。

+1

递归函数,为每个文件夹调用自身并查找文件 – Guidhouse 2011-04-21 20:37:32

回答

85

使用NSDirectoryEnumerator递归地列举你想要的目录下的文件和目录,并要求它要告诉你它是否是一个文件或目录。基于在文档中列出的例子为-[NSFileManager enumeratorAtURL:includingPropertiesForKeys:options:errorHandler:]以下:

NSFileManager *fileManager = [NSFileManager defaultManager]; 
NSURL *directoryURL = … // URL pointing to the directory you want to browse 
NSArray *keys = [NSArray arrayWithObject:NSURLIsDirectoryKey]; 

NSDirectoryEnumerator *enumerator = [fileManager 
    enumeratorAtURL:directoryURL 
    includingPropertiesForKeys:keys 
    options:0 
    errorHandler:^(NSURL *url, NSError *error) { 
     // Handle the error. 
     // Return YES if the enumeration should continue after the error. 
     return YES; 
}]; 

for (NSURL *url in enumerator) { 
    NSError *error; 
    NSNumber *isDirectory = nil; 
    if (! [url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&error]) { 
     // handle error 
    } 
    else if (! [isDirectory boolValue]) { 
     // No error and it’s not a directory; do something with the file 
    } 
} 
+2

为我节省了大量的时间:) – GoodSp33d 2014-05-06 10:09:57

+3

我相信更清洁的方式来初始化NSFileManager是使用单例方法[NSFileManager defaultManager]而不是[[[NSFileManager alloc] init] autorelease] – ProblemSlover 2015-07-23 16:44:37

+0

完美答案.. !!谢谢。 – 2016-07-15 06:07:37

25

也许你可以使用这样的事情:

+(void)openEachFileAt:(NSString*)path 
{ 
    NSString* file; 
    NSDirectoryEnumerator* enumerator = [[NSFileManager defaultManager] enumeratorAtPath:path]; 
    while (file = [enumerator nextObject]) 
    { 
    // check if it's a directory 
    BOOL isDirectory = NO; 
    NSString* fullPath = [path stringByAppendingPathComponent:file]; 
    [[NSFileManager defaultManager] fileExistsAtPath:fullPath 
             isDirectory: &isDirectory]; 
    if (!isDirectory) 
    { 
     // open your file (fullPath)… 
    } 
    else 
    { 
     [self openEachFileAt: fullPath]; 
    } 
    } 
} 
+1

这是否会正常工作?枚举很深,因此它会列出所有子目录的内容。我真的想用这个,但有没有办法将枚举数限制在当前目录? – EtienneSky 2011-05-25 02:22:29

+0

只是因为我刚刚看到这个评论:如果你不想让子dirs只是不要调用[self openEachFileAt:file];再次。 – david 2012-05-18 15:45:54

+0

当天非常晚,但只是想说感谢解决我的一个主要头痛。 – Robert 2013-03-05 16:09:55

12

这里是一个快速的版本:

func openEachFileAt(path: String) { 
    var file: String 

    var subs = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(path, error: nil) as! [String] 
    var totalFiles = subs.count 
    println(totalFiles) 
    for sub in subs { 

     if sub.rangeOfString(".DS_Store") != nil { 
      //a DS_Store file 
     } else if sub.rangeOfString(".xcassets") != nil { 
      //a xcassets file 
     } else if (sub as NSString).substringWithRange(NSRange(location: 0, length: 4)) == ".git" { 
      //a git file 
     } else if sub.pathExtension == "swift" { 
      //a swift file 
     } else if sub.pathExtension == "m" { 
      //a objc file 
     } else if sub.pathExtension == "h" { 
      //a header file 
     } else { 

     } 
     var fullPath = path.stringByAppendingPathComponent(sub) 
    } 
} 
+0

谁要求Swift? – 2015-07-01 11:57:52

+5

我正在寻找它,找不到它,然后我不得不解决它。我本来可以问一个新问题并粘贴我的答案,或只是在这里粘贴我的答案。哪一个更好? – Esqarrouth 2015-07-01 14:09:39

+0

在此留下此答案,并创建一个问题并粘贴答案。请记住标记swift而不是obj-c或可可。 – 2015-07-01 19:30:52

0

下面是使用-subpathsOfDirectoryAtPath:rootPath溶液中,用文件的URL和现代的Objective-C为空钟声&口哨。

typedef void (^FileEnumerationBlock)(NSURL *_Nonnull fileURL); 

@interface NSFileManager (Extensions) 

- (void)enumerateWithRootDirectoryURL:(nonnull NSURL *)rootURL 
          fileHandler:(FileEnumerationBlock _Nonnull)fileHandler 
           error:(NSError *_Nullable *_Nullable)error; 

@end 

@implementation NSFileManager (Extensions) 

- (void)enumerateWithRootDirectoryURL:(NSURL *)rootURL 
          fileHandler:(FileEnumerationBlock)fileHandler 
           error:(NSError **)error { 
    NSString *rootPath = rootURL.path; 
    NSAssert(rootPath != nil, @"Invalid root URL %@ (nil path)", rootURL); 

    NSArray *subs = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:rootPath 
                     error:error]; 

    if (!subs) { 
     return; 
    } 

    for (NSString *sub in subs) { 
     fileHandler([rootURL URLByAppendingPathComponent:sub]); 
    } 
} 

@end 

...和雨燕一样:

func enumerate(rootDirectoryURL rootURL: NSURL, fileHandler:(URL:NSURL)->Void) throws { 
    guard let rootPath = rootURL.path else { 
     preconditionFailure("Invalid root URL: \(rootURL)") 
    } 

    let subs = try NSFileManager.defaultManager().subpathsOfDirectoryAtPath(rootPath) 
    for sub in subs { 
     fileHandler(URL: rootURL.URLByAppendingPathComponent(sub)) 
    } 
} 
0

此代码为我工作。

NSMutableString *allHash; 

    -(NSString*)getIterate:(NSString*)path { 

     allHash = [NSMutableString stringWithString:@""]; 

     NSDirectoryEnumerator *de= [[NSFileManager defaultManager] enumeratorAtPath:path]; 
     NSString *file; 
     BOOL isDirectory; 

     for(file in de) 
     { 

      //first check if it's a file 
      NSString* fullPath = [NSString stringWithFormat:@"%@/%@",path,file]; 

      BOOL fileExistsAtPath = [[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:&isDirectory]; 
      NSLog(@"Check=>%d",fileExistsAtPath); 

      if (!isDirectory) //its a file 
      { 
       //Do with filepath 
      } 
      else{ //it's a folder, so recurse 
       [self enumerateFolder:fullPath]; 
      } 
     } 

     return allHash; 


    } 

    -(void) enumerateFolder:(NSString*)fileName 
    { 

     NSDirectoryEnumerator *de= [[NSFileManager defaultManager] enumeratorAtPath:fileName]; 
     NSString* file; 
     BOOL isDirectory; 

     for(file in de) 
     { 
      //first check if it's a file 
      BOOL fileExistsAtPath = [[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory]; 

      if (fileExistsAtPath) { 
       if (!isDirectory) //its a file 
       { 
        //Do with file 
       } 
       else{ //it's a folder, so recurse 

        [self enumerateFolder:file]; 
       } 
      } 
      else printf("\nenumeratefolder No file at path %s",[file UTF8String]); 
     } 
    }