Obtener una lista de archivos en un directorio con un globo

136

Por alguna loca razón, no puedo encontrar una manera de obtener una lista de archivos con un globo para un directorio dado.

Actualmente estoy atrapado con algo en la línea de:

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

..y luego quitar las cosas que no quiero, lo que apesta. Pero lo que realmente me gustaría es poder buscar algo como "foo * .jpg" en lugar de preguntar por el directorio completo, pero no he podido encontrar algo así.

Entonces, ¿cómo diablos lo haces?

sammich
fuente
La respuesta de Brian Webster me ayudó mucho en un tema similar. stackoverflow.com/questions/5105250/…
Wytchkraft
1
Solo una nota al margen para cualquiera que lea esto, puede resolver esto simplemente colocando sus archivos en una carpeta stackoverflow.com/questions/1762836/…
seo

Respuestas:

240

Puede lograr esto fácilmente con la ayuda de NSPredicate, así:

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

Si necesita hacerlo con NSURL, se ve así:

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];
Brian Webster
fuente
2
directoryContentsAtPath está en desuso desde iOS 2.0. Esta pregunta + respuesta son demasiado antiguas ...
Jonny
77
Simplemente seguí adelante y actualicé el ejemplo de código para usar el contenido de DirectoryDirectoryAtPath: error: en lugar de directoryContentsAtPath:
Brian Webster
55
Sí, puede agregar lógica adicional usando declaraciones OR, por ejemplo, "self ENDSWITH '.jpg' OR self ENDSWITH '.png'"
Brian Webster
2
Esto es increíble ... ¡He estado molestando con otros enfoques durante todo un día! Excelente. ¡El truco principal es saber qué buscar en StackO!
Cliff Ribaudo
3
Puede usar "pathExtension == '.xxx'" en lugar de "ENDSWITH". Mira esta respuesta
Bruno Berisso
34

Esto funciona bastante bien IOS, pero también debería 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);            
    }       
}
Matt
fuente
28

¿Qué pasa con el uso de los métodos hasSuffix y hasPrefix de NSString? Algo así como (si está buscando "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 coincidencias simples y directas como esa, sería más simple que usar una biblioteca de expresiones regulares.

John Biesnecker
fuente
Debería usar en contentsOfDirectoryAtPath:error:lugar de directoryContentsAtPathporque es deprecateddesde iOS2.0
Alex Cio
Esta es la primera respuesta en la lista para responder la pregunta, así que la voté
Guy
12

Método muy simple:

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);
SVM-RAJESH
fuente
10

Unix tiene una biblioteca que puede realizar operaciones de globalización de archivos por usted. Las funciones y los tipos se declaran en un encabezado llamado glob.h, por lo que deberá #includehacerlo. Si abre un terminal y abra la página de manual de glob escribiendo man 3 glob, obtendrá toda la información que necesita saber para usar las funciones.

A continuación se muestra un ejemplo de cómo podría llenar una matriz de archivos que coinciden con un patrón global. Cuando utilice la globfunción, debe tener en cuenta algunas cosas.

  1. Por defecto, la globfunción busca archivos en el directorio de trabajo actual. Para buscar en otro directorio, deberá anteponer el nombre del directorio al patrón global como lo hice en mi ejemplo para obtener todos los archivos /bin.
  2. Usted es responsable de limpiar la memoria asignada globllamando globfreecuando haya terminado con la estructura.

En mi ejemplo, uso las opciones predeterminadas y no hay devolución de llamada de error. La página de manual cubre todas las opciones en caso de que haya algo allí que desee usar. Si va a utilizar el código anterior, le sugiero agregarlo como una categoría NSArrayo algo así.

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

Editar: he creado una esencia en github que contiene el código anterior en una categoría llamada NSArray + Globbing .

Bryan Kyle
fuente
stringWithCString:es obsoleto. El reemplazo correcto es -[NSFileManager stringWithFileSystemRepresentation:length:], aunque creo que la mayoría de la gente lo usa stringWithUTF8String:(lo cual es más fácil pero no garantiza que sea la codificación correcta).
Peter Hosey
5

Necesita rodar su propio método para eliminar los archivos que no desea.

Esto no es fácil con las herramientas integradas, pero podría usar RegExKit Lite para ayudar a encontrar los elementos en la matriz devuelta que le interese. De acuerdo con las notas de la versión, esto debería funcionar en las aplicaciones Cocoa y Cocoa-Touch.

Aquí está el código de demostración que escribí en unos 10 minutos. Cambié el <y> a "porque no se mostraban dentro del bloque previo, pero aún funciona con las comillas. Quizás alguien que sepa más sobre formatear código aquí en StackOverflow lo corrija (¿Chris?).

Este es un proyecto de plantilla de la herramienta de línea de comandos "Herramienta básica". Si tengo mi git daemon funcionando en mi servidor de inicio, editaré esta publicación para agregar la URL del proyecto.

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

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

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

    // inserta el código aquí ...
    MTFileMatcher * matcher = [[[MTFileMatcher alloc] init] autorelease];
    [matcher getFilesMatchingRegEx: @ "^. + \\. [Jj] [Pp] [Ee]? [Gg] $" forPath: [@ "~ / Pictures" stringByExpandingTildeInPath]];

    [drenaje de la piscina];
    devuelve 0;
}

@implementation MTFileMatcher
- (nulo) getFilesMatchingRegEx: (NSString *) inRegex forPath: (NSString *) inPath;
{
    NSArray * filesAtPath = [[[NSFileManager defaultManager] directorioContentsAtPath: inPath] arrayByMatchingObjectsWithRegex: inRegex];
    NSEnumerator * itr = [filesAtPath objectEnumerator];
    NSString * obj;
    while (obj = [itr nextObject])
    {
        NSLog (obj);
    }
}
@final
marca
fuente
3

No pretendo ser un experto en el tema, pero debes tener acceso a ambos glob y wordexpla función de Objective-C, no?

Sean Bright
fuente
2

stringWithFileSystemRepresentation no parece estar disponible en iOS.

Oscar
fuente
0

Swift 5

Esto funciona para el 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)")
            }
        }
Perla Negra
fuente
0

Swift 5 para 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  {  }
        }
dengST30
fuente