2009-06-11 30 views
12

Voglio scansionare un albero di directory ed elencare tutti i file e le cartelle all'interno di ogni directory. Ho creato un programma che scarica le immagini da una webcam e le salva localmente. Questo programma crea un filtro in base al momento in cui l'immagine viene scaricata. Ora voglio scansionare queste cartelle e caricare le immagini su un server web, ma non sono sicuro di come sia possibile scansionare le directory per trovare le immagini. Se qualcuno potesse pubblicare del codice di esempio sarebbe molto utile.scansione cartella ricorsiva in C++

modificare: Io l'esecuzione di questo su un sistema Linux embedded e Non voglio usare spinta

+0

Quale sistema operatibg? –

risposta

30

Vedere man ftw per un semplice "file tree walk". Ho anche usato fnmatch in questo esempio.

#include <ftw.h> 
#include <fnmatch.h> 

static const char *filters[] = { 
    "*.jpg", "*.jpeg", "*.gif", "*.png" 
}; 

static int callback(const char *fpath, const struct stat *sb, int typeflag) { 
    /* if it's a file */ 
    if (typeflag == FTW_F) { 
     int i; 
     /* for each filter, */ 
     for (i = 0; i < sizeof(filters)/sizeof(filters[0]); i++) { 
      /* if the filename matches the filter, */ 
      if (fnmatch(filters[i], fpath, FNM_CASEFOLD) == 0) { 
       /* do something */ 
       printf("found image: %s\n", fpath); 
       break; 
      } 
     } 
    } 

    /* tell ftw to continue */ 
    return 0; 
} 

int main() { 
    ftw(".", callback, 16); 
} 

(Nemmeno compilazione testato, ma si ottiene l'idea.)

Questo è molto più semplice che affrontare DIRENT s e attraversamento ricorsivo te stesso.


Per un maggiore controllo sulla attraversamento, c'è anche fts. In questo esempio, i file di punti (file e directory con nomi che iniziano con ".") Vengono saltati, a meno che non vengano passati esplicitamente al programma come punto di partenza.

#include <fts.h> 
#include <string.h> 

int main(int argc, char **argv) { 
    char *dot[] = {".", 0}; 
    char **paths = argc > 1 ? argv + 1 : dot; 

    FTS *tree = fts_open(paths, FTS_NOCHDIR, 0); 
    if (!tree) { 
     perror("fts_open"); 
     return 1; 
    } 

    FTSENT *node; 
    while ((node = fts_read(tree))) { 
     if (node->fts_level > 0 && node->fts_name[0] == '.') 
      fts_set(tree, node, FTS_SKIP); 
     else if (node->fts_info & FTS_F) { 
      printf("got file named %s at depth %d, " 
       "accessible via %s from the current directory " 
       "or via %s from the original starting directory\n", 
       node->fts_name, node->fts_level, 
       node->fts_accpath, node->fts_path); 
      /* if fts_open is not given FTS_NOCHDIR, 
      * fts may change the program's current working directory */ 
     } 
    } 
    if (errno) { 
     perror("fts_read"); 
     return 1; 
    } 

    if (fts_close(tree)) { 
     perror("fts_close"); 
     return 1; 
    } 

    return 0; 
} 

Anche in questo caso, non è né compilazione testato né run-testato, ma ho pensato di parlarne.

+0

Il campione FTS ha funzionato alla grande. Le uniche modifiche che dovevo fare erano "ftsread" -> "fts_read" e dovevo trasmettere il risultato di fts_read a (FTSENT *). Avrei pensato che trovare codice come questo sarebbe stato più facile sul web, ma questo è stato sicuramente l'esempio più pulito che ho trovato. Grazie! – Hortitude

+0

Grazie per gli esempi, questo è utile –

+1

I valori per fts_info non sono bit singoli ... le opzioni da FTS_D a FTS_W sono definite come valori sequenziali da 1 a 14. Probabilmente è confuso per alcuni il codice come "& FTS_F" senza commento spiegando cosa succede È POSSIBILE che le persone intendano catturare FTS_F, FTS_INIT, FTS_NS, FTS_NSOK, FTS_SL, FTS_SLNONE e FTS_W qui ... ma FTS_NS o FTS_NSOK sarebbero un po 'strani. Inoltre, vedo il codice sul web che fa "& FTS_D", che non è quasi certamente quello che intendevano (ottiene FTS_ERR, FTS_DEFAULT). – darron

6

Boost.Filesystem ti permette di fare questo. Dai un'occhiata allo docs!

MODIFICA:
Se si utilizza Linux e non si desidera utilizzare Boost, sarà necessario utilizzare le funzioni C native di Linux. This page mostra molti esempi su come fare proprio questo.

+1

l'ultimo anello è rotto –

0

Penso che se è possibile utilizzare Qt/Embedded, ci sono classi QDir e QFileInfo che possono aiutare, anche se dipende se è possibile utilizzare il Qt. La domanda è quale API fornisce il tuo sistema.

1

Si desidera utilizzare le funzioni di directory dichiarate in dirent.h. Questo wikipedia page li descrive e include codice di esempio. Per la tua applicazione, una volta identificata una directory, dovrai chiamare di nuovo la funzione di elaborazione in modo ricorsivo per elaborare il contenuto della directory.

1

È inoltre possibile utilizzare glob/globfree.

+0

Più facile che leggere le directory e l'esecuzione di partite da soli, ma ancora non ricorsivo. Certo, utilizzando GLOB_ONLYDIR significa che si potrebbe evitare di trattare con DIRENTs del tutto, ma non è ancora maneggevole come FTW, e puramente basati sul nome attraversamenti sono filante. – ephemient

2

Sono della vecchia scuola, senza FTW() per me! Si tratta di greggio (è stato un po 'che ho fatto di programmazione C dritto), e un sacco di roba è hardcoded, e probabilmente ho incasinato i miei calcoli di lunghezza per la strnc *() funzioni, ma si ottiene l'idea. C'è un esempio simile in K & R btw.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#include <sys/types.h> 
#include <dirent.h> 

void listdir(char* dirname, int lvl); 

int main(int argc, char** argv) 
{ 

    if (argc != 2) { 
    fprintf(stderr, "Incorrect usage!\n"); 
    exit(-1); 
    } 
    listdir(argv[1], 0); 


    return 0; 
} 

void listdir(char* dirname, int lvl) 
{ 

    int i; 
    DIR* d_fh; 
    struct dirent* entry; 
    char longest_name[4096]; 

    while((d_fh = opendir(dirname)) == NULL) { 
    fprintf(stderr, "Couldn't open directory: %s\n", dirname); 
    exit(-1); 
    } 

    while((entry=readdir(d_fh)) != NULL) { 

    /* Don't descend up the tree or include the current directory */ 
    if(strncmp(entry->d_name, "..", 2) != 0 && 
     strncmp(entry->d_name, ".", 1) != 0) { 

     /* If it's a directory print it's name and recurse into it */ 
     if (entry->d_type == DT_DIR) { 
     for(i=0; i < 2*lvl; i++) { 
      printf(" "); 
     } 
     printf("%s (d)\n", entry->d_name); 

     /* Prepend the current directory and recurse */ 
     strncpy(longest_name, dirname, 4095); 
     strncat(longest_name, "/", 4095); 
     strncat(longest_name, entry->d_name, 4095); 
     listdir(longest_name, lvl+1); 
     } 
     else { 

     /* Print some leading space depending on the directory level */ 
     for(i=0; i < 2*lvl; i++) { 
      printf(" "); 
     } 
     printf("%s\n", entry->d_name); 
     } 
    } 
    } 

    closedir(d_fh); 

    return; 
} 
+0

strncmp (name, ".", 1) escluderà i dot-file. Inoltre, probabilmente è meglio saltare (con avvertimento) piuttosto che provare a procedere con un nome troncato. Infine, invece di un ciclo, c'è questo trucco carino per la stampa dell'indentazione: static char spaces [] = ""; printf ("% s", spazi [max (0, strlen (spazi) - count)]); – ephemient