Obtendo uma lista de arquivos em um diretório com um glob


136

Por alguma razão maluca, não consigo encontrar uma maneira de obter uma lista de arquivos com um glob para um determinado diretório.

Atualmente, estou preso a algo como:

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

..e depois retirar as coisas que eu não quero, o que é uma merda. Mas o que eu realmente gostaria é poder procurar algo como "foo * .jpg" em vez de solicitar o diretório inteiro, mas não consegui encontrar nada parecido.

Então, como diabos você faz isso?


A resposta de Brian Webster me ajudou muito em uma questão semelhante. stackoverflow.com/questions/5105250/…
Wytchkraft

1
Basta dar uma nota para quem estiver lendo isso, você poderá resolver isso colocando seus arquivos em uma pasta stackoverflow.com/questions/1762836/…
seo

Respostas:


240

Você pode conseguir isso facilmente com a ajuda do NSPredicate, da seguinte forma:

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 você precisar fazer isso com o NSURL, será assim:

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 está obsoleto desde o iOS 2.0. Esta pergunta de resposta + são muito antigas ...
Jonny

7
Apenas fui em frente e atualizei o exemplo de código para usar contentsOfDirectoryAtPath: error: em vez de directoryContentsAtPath:
Brian Webster

5
Sim, você pode adicionar lógica adicional usando as instruções OR, por exemplo, "self ENDSWITH '.jpg' OR self ENDSWITH '.png'"
Brian Webster

2
Isso é incrível ... Estou mijando com outras abordagens há um dia inteiro agora! Ótimo. O principal truque é apenas saber o que procurar no StackO!
Cliff Ribaudo

3
Você pode usar o "pathExtension == '.xxx'" em vez de "ENDSWITH". Veja esta resposta
Bruno Berisso

34

Isso funciona muito bem para IOS, mas também deve funcionar 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

Que tal usar os métodos hasSuffix e hasPrefix do NSString? Algo como (se você estiver procurando por "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

    }
}

Para correspondências simples e diretas como essa, seria mais simples do que usar uma biblioteca regex.


Você deve usar em contentsOfDirectoryAtPath:error:vez de directoryContentsAtPathporque é deprecateddesde iOS2.0 #
Alex Cio 27/02

Esta é a primeira resposta na lista para responder à pergunta, por isso votei-lo
Guy

12

Método muito mais simples:

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

O Unix possui uma biblioteca que pode executar operações de globbing de arquivos para você. As funções e os tipos são declarados em um cabeçalho chamado glob.h, então você precisará #includedisso. Se abrir um terminal e abrir a página de manual do glob digitando, man 3 globvocê obterá todas as informações necessárias para usar as funções.

Abaixo está um exemplo de como você pode preencher uma matriz com os arquivos que correspondem a um padrão de globbing. Ao usar a globfunção, lembre-se de algumas coisas.

  1. Por padrão, a globfunção procura por arquivos no diretório de trabalho atual. Para pesquisar em outro diretório, você precisará acrescentar o nome do diretório ao padrão globbing, como fiz no exemplo para obter todos os arquivos /bin.
  2. Você é responsável por limpar a memória alocada globchamando globfreequando terminar a estrutura.

No meu exemplo, eu uso as opções padrão e nenhum retorno de chamada de erro. A página de manual cobre todas as opções, caso haja algo que você queira usar. Se você usar o código acima, sugiro adicioná-lo como uma categoria NSArrayou algo parecido.

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

Edit: Eu criei uma essência no github que contém o código acima em uma categoria chamada NSArray + Globbing .


stringWithCString:está obsoleto. A substituição correta é -[NSFileManager stringWithFileSystemRepresentation:length:], embora eu ache que a maioria das pessoas usa stringWithUTF8String:(o que é mais fácil, mas não é garantido que seja a codificação correta).
Peter Hosey

5

Você precisa rolar seu próprio método para eliminar os arquivos que não deseja.

Isso não é fácil com as ferramentas integradas, mas você pode usar RegExKit Lite para ajudar a encontrar os elementos na matriz retornada em que está interessado. De acordo com as notas de versão, isso deve funcionar nos aplicativos Cocoa e Cocoa-Touch.

Aqui está o código de demonstração que escrevi em cerca de 10 minutos. Alterei <e> para "porque eles não estavam aparecendo dentro do pré-bloco, mas ainda funciona com as aspas. Talvez alguém que saiba mais sobre a formatação do código aqui no StackOverflow corrija isso (Chris?).

Este é um projeto de modelo do Utilitário de Linha de Comando da "Foundation Tool". Se eu instalar o meu daemon git no meu servidor doméstico, editarei esta postagem para adicionar a URL do projeto.

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

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

int main (int argc, const char * argv [])
{
    NSAutoreleasePool * pool = [[alocação de NSAutoreleasePool] init];

    // insere o código aqui ...
    MTFileMatcher * matcher = [[[alocação de MTFileMatcher] init] autorelease]];
    [matcher getFilesMatchingRegEx: @ "^. + \\. [Jj] [Pp] [Ee]? [Gg] $" forPath: [@ "~ / Pictures" stringByExpandingTildeInPath]];

    [esgoto da piscina];
    retornar 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);
    }
}
@fim

3

Não vou fingir ser um especialista no assunto, mas você deve ter acesso às funções from globe wordexpdo objetivo-c, não?


2

stringWithFileSystemRepresentation não parece estar disponível no iOS.


0

Swift 5

Isso funciona para o cacau

        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 para cacau

        // 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  {  }
        }
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.