Ottenere un elenco di file in una directory con un glob


136

Per qualche pazza ragione non riesco a trovare un modo per ottenere un elenco di file con un glob per una determinata directory.

Al momento sono bloccato con qualcosa del genere:

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

..e poi togliendo le cose che non voglio, il che fa schifo. Ma quello che mi piacerebbe davvero è poter cercare qualcosa come "foo * .jpg" invece di chiedere l'intera directory, ma non sono stato in grado di trovare nulla del genere.

Quindi come diamine lo fai?


La risposta di Brian Webster mi ha aiutato molto in un problema simile. stackoverflow.com/questions/5105250/...
Wytchkraft

1
Solo una nota a margine a chiunque legga questo, potresti essere in grado di risolverlo semplicemente mettendo i tuoi file in una cartella stackoverflow.com/questions/1762836/…
seo

Risposte:


240

Puoi farlo abbastanza facilmente con l'aiuto di NSPredicate, in questo modo:

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

Se devi farlo con NSURL, invece, si presenta così:

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 è obsoleto da iOS 2.0. Questa domanda + risposta sono troppo vecchie ...
Jonny il

7
Sono appena andato avanti e ho aggiornato l'esempio di codice per utilizzare contentsOfDirectoryAtPath: errore: anziché directoryContentsAtPath:
Brian Webster,

5
Sì, puoi aggiungere una logica aggiuntiva usando le istruzioni OR, ad esempio "self ENDSWITH '.jpg' OR self ENDSWITH '.png'"
Brian Webster,

2
È fantastico ... Mi sto incazzando con altri approcci da un giorno intero! Grande. Il trucco principale è sapere cosa cercare su StackO!
Cliff Ribaudo,

3
È possibile utilizzare "pathExtension == '.xxx'" anziché "ENDSWITH". Guarda questa risposta
Bruno Berisso,

34

Funziona abbastanza bene per IOS, ma dovrebbe funzionare anche per 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

Che dire dell'utilizzo dei metodi hasSuffix e hasPrefix di NSString? Qualcosa di simile (se stai cercando "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

    }
}

Per corrispondenze semplici e dirette del genere sarebbe più semplice che utilizzare una libreria regex.


Dovresti usare contentsOfDirectoryAtPath:error:invece directoryContentsAtPathperché perché è deprecateddal iOS2.0
Alex Cio,

Questa è la prima risposta nella lista a rispondere alla domanda, quindi ho votato a favore
Guy

12

Metodo molto più semplice:

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 ha una libreria in grado di eseguire per te operazioni di globbing dei file. Le funzioni e i tipi sono dichiarati in un'intestazione chiamata glob.h, quindi è necessario #include. Se apri un terminale e apri la pagina man per glob digitando man 3 globotterrai tutte le informazioni che devi sapere per usare le funzioni.

Di seguito è riportato un esempio di come è possibile popolare un array con i file che corrispondono a un modello globbing. Quando si utilizza la globfunzione, è necessario tenere presente alcune cose.

  1. Per impostazione predefinita, la globfunzione cerca i file nella directory di lavoro corrente. Per cercare un'altra directory devi anteporre il nome della directory al modello globbing come ho fatto nel mio esempio per ottenere tutti i file /bin.
  2. Sei responsabile della pulizia della memoria allocata globchiamando chiamando globfreeal termine della struttura.

Nel mio esempio uso le opzioni predefinite e nessun errore di richiamata. La pagina man copre tutte le opzioni nel caso ci sia qualcosa che vuoi usare. Se hai intenzione di utilizzare il codice sopra, ti suggerirei di aggiungerlo come categoria NSArrayo qualcosa del genere.

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

Modifica: ho creato un gist su github che contiene il codice sopra in una categoria chiamata NSArray + Globbing .


stringWithCString:è deprecato. La sostituzione corretta è -[NSFileManager stringWithFileSystemRepresentation:length:], anche se penso che la maggior parte delle persone usi stringWithUTF8String:(che è più facile ma non è garantito che sia la codifica corretta).
Peter Hosey,

5

Devi eliminare il tuo metodo per eliminare i file che non desideri.

Questo non è facile con gli strumenti integrati, ma potresti usare RegExKit Lite per aiutarti a trovare gli elementi nell'array restituito che ti interessano. Secondo le note di rilascio, questo dovrebbe funzionare sia nelle applicazioni Cocoa che Cocoa-Touch.

Ecco il codice demo che ho scritto in circa 10 minuti. Ho cambiato <e> in "perché non erano presenti all'interno del pre-blocco, ma funziona ancora con le virgolette. Forse qualcuno che sa di più sulla formattazione del codice qui su StackOverflow lo correggerà (Chris?).

Questo è un progetto modello di utilità della riga di comando "Strumento di base". Se avrò il mio demone git attivo e funzionante sul mio server di casa, modificherò questo post per aggiungere l'URL per il progetto.

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

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

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

    // inserisci il codice qui ...
    MTFileMatcher * matcher = [[[[MTFileMatcher alloc] init] rilascio automatico];
    [matcher getFilesMatchingRegEx: @ "^. + \\. [Jj] [Pp] [Ee]? [Gg] $" forPath: [@ "~ / Pictures" stringByExpandingTildeInPath]];

    [drenaggio della piscina];
    ritorna 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);
    }
}
@fine

3

Io non pretendo di essere un esperto sul tema, ma si dovrebbe avere accesso sia al globe wordexpfunzione dal Objective-C, no?


2

stringWithFileSystemRepresentation non sembra essere disponibile in iOS.


0

Swift 5

Questo funziona per il cacao

        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 per cacao

        // 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  {  }
        }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.