A maneira mais rápida é um programa criado para esse fim, como este:
#include <stdio.h>
#include <dirent.h>
int main(int argc, char *argv[]) {
DIR *dir;
struct dirent *ent;
long count = 0;
dir = opendir(argv[1]);
while((ent = readdir(dir)))
++count;
closedir(dir);
printf("%s contains %ld files\n", argv[1], count);
return 0;
}
Nos meus testes, sem considerar o cache, executei cada uma delas cerca de 50 vezes cada vez no mesmo diretório, repetidamente, para evitar a distorção dos dados baseados em cache, e obtive aproximadamente os seguintes números de desempenho (em tempo real):
ls -1 | wc - 0:01.67
ls -f1 | wc - 0:00.14
find | wc - 0:00.22
dircnt | wc - 0:00.04
Esse último,, dircnt
é o programa compilado a partir da fonte acima.
EDIT 26-09-2016
Devido à demanda popular, reescrevi este programa para ser recursivo; portanto, ele cai em subdiretórios e continua a contar arquivos e diretórios separadamente.
Como fica claro que algumas pessoas querem saber como fazer tudo isso, tenho muitos comentários no código para tentar tornar óbvio o que está acontecendo. Eu escrevi e testei no Linux de 64 bits, mas deve funcionar em qualquer sistema compatível com POSIX, incluindo o Microsoft Windows. Relatórios de erros são bem-vindos; É um prazer atualizá-lo se você não conseguir fazê-lo funcionar no seu AIX ou OS / 400 ou o que for.
Como você pode ver, é muito mais complicado do que o original e necessariamente o mesmo: pelo menos uma função deve existir para ser chamada recursivamente, a menos que você queira que o código se torne muito complexo (por exemplo, gerenciando uma pilha de subdiretórios e processando-a em um único loop). Como temos que verificar os tipos de arquivo, as diferenças entre diferentes sistemas operacionais, bibliotecas padrão etc. entram em cena, por isso escrevi um programa que tenta ser utilizável em qualquer sistema em que ele seja compilado.
Há muito pouca verificação de erros, e a count
própria função realmente não relata erros. As únicas chamadas que realmente podem falhar são opendir
e stat
(se você não tiver sorte e já possui um sistema que já dirent
contém o tipo de arquivo). Eu não sou paranóico sobre como verificar o comprimento total dos caminhos de subdiretórios, mas, teoricamente, o sistema não deve permitir qualquer nome caminho que é maior do que do que PATH_MAX
. Se houver preocupações, eu posso consertar isso, mas é apenas mais um código que precisa ser explicado para alguém aprendendo a escrever C. Este programa pretende ser um exemplo de como mergulhar nos subdiretórios recursivamente.
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/stat.h>
#if defined(WIN32) || defined(_WIN32)
#define PATH_SEPARATOR '\\'
#else
#define PATH_SEPARATOR '/'
#endif
/* A custom structure to hold separate file and directory counts */
struct filecount {
long dirs;
long files;
};
/*
* counts the number of files and directories in the specified directory.
*
* path - relative pathname of a directory whose files should be counted
* counts - pointer to struct containing file/dir counts
*/
void count(char *path, struct filecount *counts) {
DIR *dir; /* dir structure we are reading */
struct dirent *ent; /* directory entry currently being processed */
char subpath[PATH_MAX]; /* buffer for building complete subdir and file names */
/* Some systems don't have dirent.d_type field; we'll have to use stat() instead */
#if !defined ( _DIRENT_HAVE_D_TYPE )
struct stat statbuf; /* buffer for stat() info */
#endif
/* fprintf(stderr, "Opening dir %s\n", path); */
dir = opendir(path);
/* opendir failed... file likely doesn't exist or isn't a directory */
if(NULL == dir) {
perror(path);
return;
}
while((ent = readdir(dir))) {
if (strlen(path) + 1 + strlen(ent->d_name) > PATH_MAX) {
fprintf(stdout, "path too long (%ld) %s%c%s", (strlen(path) + 1 + strlen(ent->d_name)), path, PATH_SEPARATOR, ent->d_name);
return;
}
/* Use dirent.d_type if present, otherwise use stat() */
#if defined ( _DIRENT_HAVE_D_TYPE )
/* fprintf(stderr, "Using dirent.d_type\n"); */
if(DT_DIR == ent->d_type) {
#else
/* fprintf(stderr, "Don't have dirent.d_type, falling back to using stat()\n"); */
sprintf(subpath, "%s%c%s", path, PATH_SEPARATOR, ent->d_name);
if(lstat(subpath, &statbuf)) {
perror(subpath);
return;
}
if(S_ISDIR(statbuf.st_mode)) {
#endif
/* Skip "." and ".." directory entries... they are not "real" directories */
if(0 == strcmp("..", ent->d_name) || 0 == strcmp(".", ent->d_name)) {
/* fprintf(stderr, "This is %s, skipping\n", ent->d_name); */
} else {
sprintf(subpath, "%s%c%s", path, PATH_SEPARATOR, ent->d_name);
counts->dirs++;
count(subpath, counts);
}
} else {
counts->files++;
}
}
/* fprintf(stderr, "Closing dir %s\n", path); */
closedir(dir);
}
int main(int argc, char *argv[]) {
struct filecount counts;
counts.files = 0;
counts.dirs = 0;
count(argv[1], &counts);
/* If we found nothing, this is probably an error which has already been printed */
if(0 < counts.files || 0 < counts.dirs) {
printf("%s contains %ld files and %ld directories\n", argv[1], counts.files, counts.dirs);
}
return 0;
}
EDIT 2017-01-17
Incorporei duas alterações sugeridas por @FlyingCodeMonkey:
- Use em
lstat
vez de stat
. Isso mudará o comportamento do programa se você tiver diretórios com links simbólicos no diretório que está digitalizando. O comportamento anterior era que o subdiretório (vinculado) teria sua contagem de arquivos adicionada à contagem geral; o novo comportamento é que o diretório vinculado contará como um único arquivo e seu conteúdo não será contado.
- Se o caminho de um arquivo for muito longo, uma mensagem de erro será emitida e o programa será interrompido.
EDIT 2017-06-29
Com alguma sorte, esta será a última edição desta resposta :)
Copiei esse código em um repositório do GitHub para facilitar um pouco a obtenção do código (em vez de copiar / colar, você pode simplesmente fazer o download do código-fonte ), além de facilitar a sugestão de uma modificação enviando um pull -requisição do GitHub.
A fonte está disponível sob a Licença Apache 2.0. Patches * bem-vindos!
- "patch" é o que pessoas idosas como eu chamam de "solicitação pull".