การรับรายการไฟล์ในไดเรกทอรีด้วย glob


136

ด้วยเหตุผลบางอย่างที่บ้าฉันไม่สามารถหาวิธีรับรายชื่อไฟล์ด้วย glob สำหรับไดเรกทอรีที่กำหนดได้

ฉันกำลังติดอยู่กับบางสิ่งบางอย่างตามแนวของ:

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

คำตอบ:


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
directoryContentsAtPath เลิกใช้แล้วตั้งแต่ iOS 2.0 คำถามนี้คำตอบ + จะเก่าเกินไป ...
จอนนี่

7
เพิ่งไปข้างหน้าและอัปเดตตัวอย่างโค้ดเพื่อใช้ contentOfDirectoryAtPath: ข้อผิดพลาด: แทนที่จะเป็น directoryContentsAtPath:
Brian Webster

5
ใช่คุณสามารถเพิ่มตรรกะเพิ่มเติมโดยใช้คำสั่ง OR เช่น "self ENDSWITH '.jpg' หรือตัวเอง ENDSWITH '.png'"
Brian Webster

2
มันยอดเยี่ยมมาก ... ข้าได้เข้ามาใกล้กับวิธีอื่นมาทั้งวันแล้ว! ยิ่งใหญ่ เคล็ดลับหลักคือเพียงรู้ว่าจะค้นหาใน StackO!
Cliff Ribaudo

3
คุณสามารถใช้ "pathExtension == '.xxx'" แทน "ENDSWITH" ดูคำตอบ
Bruno Berisso

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

แล้วการใช้วิธี hasSuffix และ hasPrefix ของ NSString ล่ะ สิ่งที่ชอบ (หากคุณกำลังค้นหา "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

    }
}

สำหรับการจับคู่แบบตรงไปตรงมาอย่างง่าย ๆ มันจะง่ายกว่าการใช้ไลบรารี regex


คุณควรใช้contentsOfDirectoryAtPath:error:แทนdirectoryContentsAtPathเพราะมันเป็นdeprecatedตั้งแต่iOS2.0
Alex 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มัน ถ้าเปิดเทอร์มินัลให้เปิด man page สำหรับ glob โดยพิมพ์man 3 globคุณจะได้รับข้อมูลทั้งหมดที่คุณจำเป็นต้องรู้เพื่อใช้ฟังก์ชั่น

ด้านล่างเป็นตัวอย่างของวิธีที่คุณสามารถเติมอาร์เรย์ของไฟล์ที่ตรงกับรูปแบบกลม เมื่อใช้globฟังก์ชั่นมีบางสิ่งที่คุณต้องจำไว้

  1. โดยค่าเริ่มต้นglobฟังก์ชั่นการค้นหาไฟล์ในไดเรกทอรีการทำงานปัจจุบัน เพื่อที่จะค้นหาไดเรกทอรีอื่นคุณจะต้องย่อหน้าชื่อไดเรกทอรีกับรูปแบบ globbing /binที่สุดเท่าที่ฉันเคยทำในตัวอย่างของฉันที่จะได้รับไฟล์ทั้งหมดที่อยู่ใน
  2. คุณมีหน้าที่ในการล้างหน่วยความจำที่จัดสรรglobโดยการโทรglobfreeเมื่อคุณทำกับโครงสร้าง

ในตัวอย่างของฉันฉันใช้ตัวเลือกเริ่มต้นและไม่มีข้อผิดพลาดในการโทรกลับ man page ครอบคลุมตัวเลือกทั้งหมดในกรณีที่มีบางสิ่งที่คุณต้องการใช้ หากคุณจะใช้รหัสข้างต้นฉันขอแนะนำให้เพิ่มเป็นหมวดหมู่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:(ซึ่งง่ายกว่า แต่ไม่รับประกันว่าจะเป็นการเข้ารหัสที่ถูกต้อง)
Peter Hosey

5

คุณต้องหมุนวิธีการของคุณเองเพื่อกำจัดไฟล์ที่คุณไม่ต้องการ

นี่ไม่ใช่เรื่องง่ายด้วยเครื่องมือในตัว แต่คุณสามารถใช้RegExKit Liteเพื่อช่วยในการค้นหาองค์ประกอบในอาร์เรย์ที่ส่งคืนที่คุณสนใจตามบันทึกย่อประจำรุ่นนี้ควรทำงานได้ทั้งในแอปพลิเคชัน Cocoa และ Cocoa-Touch

นี่คือรหัสตัวอย่างที่ฉันเขียนขึ้นในเวลาประมาณ 10 นาที ฉันเปลี่ยน <และ> เป็น "เพราะพวกเขาไม่ได้ปรากฏอยู่ในบล็อกก่อนหน้า แต่ก็ยังใช้งานได้กับเครื่องหมายคำพูดบางทีใครบางคนที่รู้เพิ่มเติมเกี่ยวกับการจัดรูปแบบโค้ดที่นี่ใน StackOverflow จะแก้ไขสิ่งนี้ (Chris?)

นี่คือโครงการแม่แบบ "เครื่องมือพื้นฐาน" อรรถประโยชน์บรรทัดคำสั่ง หากฉันได้รับ git daemon ของฉันและทำงานบนเซิร์ฟเวอร์ที่บ้านของฉันฉันจะแก้ไขโพสต์นี้เพื่อเพิ่ม URL สำหรับโครงการ

#import "Foundation / Foundation.h"
#import "RegexKit / RegexKit.h"

@interface MTFileMatcher: NSObject 
{
}
- (เป็นโมฆะ) getFilesMatchingRegEx: (NSString *) inRegex forPath: (NSString *) inPath;
@end

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: [@ "~ / รูปภาพ" stringByExpandingTildeInPath]

    [ท่อระบายน้ำสระว่ายน้ำ];
    กลับ 0
}

@implementation MTFileMatcher
- (เป็นโมฆะ) getFilesMatchingRegEx: (NSString *) inRegex forPath: (NSString *) inPath;
{
    NSArray * filesAtPath = [[[NSFileManager defaultManager] directoryContentsAtPath: inPath] arrayByMatchingObjectsWithRegex: inRegex];
    NSEnumerator * itr = [filesAtPath objectEnumerator];
    NSString * obj;
    ในขณะที่ (obj = [itr nextObject])
    {
        NSLog (obj);
    }
}
@end

3

ฉันจะไม่แกล้งทำเป็นเป็นผู้เชี่ยวชาญในหัวข้อ แต่คุณควรมีสิทธิ์เข้าถึงทั้งสองglobและwordexpฟังก์ชั่นจากวัตถุประสงค์ -c ไม่?



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  {  }
        }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.