Estou tentando descobrir a melhor maneira de encontrar o número de arquivos em um diretório específico quando há um número muito grande de arquivos (> 100.000).
Quando existem muitos arquivos, a execução ls | wc -l
leva muito tempo para ser executada. Acredito que seja porque está retornando os nomes de todos os arquivos. Estou tentando pegar o mínimo possível de E / S do disco.
Eu experimentei alguns scripts shell e Perl sem sucesso. Alguma ideia?
Respostas:
Por padrão,
ls
classifica os nomes, o que pode demorar um pouco, se houver muitos deles. Também não haverá saída até que todos os nomes sejam lidos e classificados. Use als -f
opção para desativar a classificação.Note-se que isso também vai permitir que
-a
, por isso.
,..
e outros arquivos começando com.
será contado.fonte
ls
.stat()
chamadals
em todos os arquivos.find
Não fazstat()
assim, ele funciona mais rápido.ls -f
também nãostat()
. Mas é claro que ambosls
efind
chamarstat()
quando certas opções são usadas, comols -l
oufind -mtime
.ls -fR | wc -l
A maneira mais rápida é um programa criado para esse fim, como este:
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):
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ãoopendir
estat
(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 quePATH_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.EDIT 2017-01-17
Incorporei duas alterações sugeridas por @FlyingCodeMonkey:
lstat
vez destat
. 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.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!
fonte
gcc -o dircnt dircnt.c
e uso é assim./dircnt some_dir
Você tentou encontrar? Por exemplo:
fonte
find /usr/share | wc -l
(~ 137.000 arquivos) é cerca de 25% mais rápido quels -R /usr/share | wc -l
(~ 160.000 linhas, incluindo nomes de dir, totais de dir e linhas em branco) na primeira execução de cada uma e pelo menos duas vezes mais rápido ao comparar execuções subsequentes (armazenadas em cache).find
é mais rápido do quels
é por causa de como você está usandols
. Se você parar de classificarls
efind
tiver desempenho semelhante.find, ls e perl testados em 40.000 arquivos: a mesma velocidade (embora eu não tenha tentado limpar o cache):
e com perl opendir / readdir, ao mesmo tempo:
observação: usei / bin / ls -f para ignorar a opção de alias, que pode diminuir um pouco e -f para evitar a ordenação de arquivos. ls sem -f é duas vezes mais lento que o find / perl, exceto se ls for usado com -f, parece que é o mesmo tempo:
Eu também gostaria de ter algum script para perguntar diretamente ao sistema de arquivos sem todas as informações desnecessárias.
testes baseados na resposta de Peter van der Heijden, glenn jackman e mark4o.
Thomas
fonte
ls -l | wc -l
uma pasta em um HDD externo de 2,5 "com arquivos de 1M, leva cerca de 3 minutos para a operação terminar. Na segunda vez, leva 12 segundos IIRC. Além disso, isso também pode depender do seu sistema de arquivos. I estava usandoBtrfs
.$ time perl -e 'opendir D, "."; @files = readdir D; closedir D; print scalar(@files)."\n"' 1315029 real 0m0.580s user 0m0.302s sys 0m0.275s
Você pode alterar a saída com base em seus requisitos, mas aqui está uma linha que eu escrevi para contar recursivamente e informar o número de arquivos em uma série de diretórios numerados.
Ele procura recursivamente todos os arquivos (não diretórios) no diretório especificado e retorna os resultados em um formato semelhante a hash. Ajustes simples no comando find podem tornar o tipo de arquivo que você deseja contar mais específico, etc.
Resultados em algo como isto:
fonte
ls -1 ${dir}
não funcionará corretamente sem mais espaços. Além disso, não há garantia de que o nome retornado porls
possa ser passadofind
, poisls
evita caracteres não imprimíveis para consumo humano. (mkdir $'oddly\nnamed\ndirectory'
se você quiser um caso de teste particularmente interessante). Veja Por que você não deve analisar a saída de ls (1)Surpreendentemente para mim, uma descoberta simples é muito comparável a ls -f
versus
Obviamente, os valores na terceira casa decimal mudam um pouco toda vez que você executa um desses, então são basicamente idênticos. Observe, no entanto, que
find
retorna uma unidade extra, porque conta o próprio diretório real (e, como mencionado anteriormente,ls -f
retorna duas unidades extras, pois também conta. E ..).fonte
Apenas adicionando isso por uma questão de integridade. A resposta correta, obviamente, já foi postada por outra pessoa, mas você também pode obter uma contagem de arquivos e diretórios com o programa em árvore.
Execute o comando
tree | tail -n 1
para obter a última linha, que dirá algo como "763 diretórios, arquivos 9290". Isso conta arquivos e pastas recursivamente, excluindo arquivos ocultos, que podem ser adicionados com o sinalizador-a
. Para referência, levou 4,8 segundos no meu computador para que a árvore contasse todo o diretório doméstico, que era 24777 diretórios, 238680 arquivos.find -type f | wc -l
demorou 5,3 segundos, meio segundo a mais, então acho que a árvore é bastante competitiva em termos de velocidade.Contanto que você não tenha subpastas, o tree é uma maneira rápida e fácil de contar os arquivos.
Além disso, e apenas por diversão, você pode usar
tree | grep '^├'
para mostrar apenas os arquivos / pastas no diretório atual - esta é basicamente uma versão muito mais lenta dols
.fonte
Brew install tail
para OS X.tail
já deve estar instalado no seu sistema Mac OS X.Contagem rápida de arquivos do Linux
A contagem mais rápida de arquivos linux que conheço é
Não há necessidade de chamar grep! Mas, como mencionado, você deve ter um novo banco de dados (atualizado diariamente por um trabalho cron ou manual por
sudo updatedb
).De man localizar
Além disso, você deve saber que também conta os diretórios como arquivos!
BTW: Se você quiser uma visão geral dos seus arquivos e diretórios no seu sistema, digite
Ele gera o número de diretórios, arquivos etc.
fonte
Escrevendo isso aqui, pois não tenho pontos de reputação suficientes para comentar uma resposta, mas estou autorizado a deixar minha própria resposta, o que não faz sentido. De qualquer forma...
Em relação à resposta de Christopher Schultz , sugiro alterar stat para lstat e possivelmente adicionar uma verificação de limites para evitar o estouro de buffer:
A sugestão para usar lstat é evitar seguir links simbólicos que podem levar a ciclos se um diretório contiver um link simbólico para um diretório pai.
fonte
lstat
era uma boa sugestão e você merece carma por isso. Essa sugestão foi incorporada ao meu código postado acima e, agora, no GitHub.Você poderia tentar se usar
opendir()
ereaddir()
emPerl
é mais rápido. Para um exemplo dessas funções, veja aquifonte
Esta resposta aqui é mais rápida do que quase tudo nesta página para diretórios muito grandes e muito aninhados:
https://serverfault.com/a/691372/84703
locate -r '.' | grep -c "^$PWD"
fonte
locate -c -r '/path'
como na solução deEu vim aqui ao tentar contar os arquivos em um conjunto de dados de ~ 10K pastas com ~ 10K arquivos cada. O problema de muitas das abordagens é que elas implicitamente registram arquivos de 100 milhões, o que leva idades.
Tomei a liberdade de estender a abordagem de christopher-schultz, para que ele suporte a passagem de diretórios via args (sua abordagem recursiva também usa stat).
Coloque o seguinte no arquivo
dircnt_args.c
:Depois de um,
gcc -o dircnt_args dircnt_args.c
você pode invocá-lo assim:Em arquivos de 100 milhões de pastas com 10 mil cópias, o processo acima é concluído rapidamente (~ 5 minutos para a primeira execução, acompanhamento no cache: ~ 23 s).
A única outra abordagem que terminou em menos de uma hora foi sl com cerca de 1 min em cache de:
ls -f /your/dirs/* | wc -l
. A contagem está desativada em algumas linhas novas por dir ...Além do esperado, nenhuma das minhas tentativas
find
retornou em uma hora: - /fonte
A maneira mais rápida no linux (a questão é marcada como linux) é usar a chamada direta do sistema. Aqui está um pequeno programa que conta arquivos (apenas, sem diretórios) em um diretório. Você pode contar milhões de arquivos e é cerca de 2,5 vezes mais rápido que "ls -f" e 1,3 a 1,5 vezes mais rápido que a resposta de Christopher Schultz.
PS: Não é recursivo, mas você pode modificá-lo para conseguir isso.
fonte
opendir
/readdir
, mas suspeito que tudo se resume ao mesmo código no final. Fazer chamadas do sistema dessa maneira também não é portátil e, como a ABI do Linux não é estável, não é garantido que um programa compilado em um sistema funcione corretamente em outro (embora seja um bom conselho compilar qualquer coisa da fonte em qualquer sistema * NIX IMO ) Se a velocidade é fundamental, esta é uma boa solução se ela realmente melhorar a velocidade - eu não comparei os programas separadamente.ls
gasta mais tempo classificando os nomes dos arquivos, usar-f
para desativar a classificação economizará algum tempo:ou você pode usar
find
:fonte
Percebi que não usar no processamento de memória quando você tem uma quantidade enorme de dados é mais rápido do que "canalizar" os comandos. Então eu salvei o resultado em um arquivo e depois o analisei
fonte
Você deve usar "getdents" no lugar de ls / find
Aqui está um artigo muito bom que descreveu a abordagem getdents.
http://be-n.com/spw/you-can-list-a-million-files-in-a-directory-but-not-with-ls.html
Aqui está o extrato:
sl e praticamente todos os outros métodos para listar um diretório (incluindo python os.listdir, find.) dependem da libc readdir (). No entanto, readdir () lê apenas 32K de entradas de diretório por vez, o que significa que se você tiver muitos arquivos no mesmo diretório (por exemplo, 500M de entradas de diretório), levará um tempo incrivelmente longo para ler todas as entradas de diretório , especialmente em um disco lento. Para diretórios que contêm um grande número de arquivos, você precisará ir além das ferramentas que dependem de readdir (). Você precisará usar o syscall getdents () diretamente, em vez dos métodos auxiliares da libc.
Podemos encontrar o código C para listar os arquivos usando getdents () a partir daqui :
Há duas modificações que você precisará fazer para listar rapidamente todos os arquivos em um diretório.
Primeiro, aumente o tamanho do buffer de X para algo como 5 megabytes.
Em seguida, modifique o loop principal onde ele imprime as informações sobre cada arquivo no diretório para ignorar entradas com inode == 0. Fiz isso adicionando
No meu caso, também me importei apenas com os nomes de arquivo no diretório, então também reescrevi a instrução printf () para imprimir apenas o nome do arquivo.
Compile-o (ele não precisa de bibliotecas externas, por isso é super simples de fazer)
Agora apenas corra
fonte
readdir()
não é realmente lento. Preciso de uma figura sólida antes de acreditar que vale a pena jogar fora a portabilidade para esse ganho de desempenho.Prefiro o seguinte comando para acompanhar as alterações no número de arquivos em um diretório.
O comando manterá uma janela aberta para rastrear o número de arquivos que estão no diretório com uma taxa de atualização de 0,1 s.
fonte
ls | wc -l
terminará em uma pasta com milhares ou milhões de arquivos em 0,01s? até o seuls
é extremamente ineficiente em comparação com outras soluções. E o OP quer apenas obter a contagem, não sentado lá olhando para a saída mudandowatch
manual após esse comentário e vi que 0,01s (não 0,1s) é um número irreal, porque a taxa de atualização da maioria das telas de PC é de apenas 60Hz, e isso não responde à pergunta de forma alguma. O OP perguntou sobre "Contagem rápida de arquivos do Linux para um grande número de arquivos". Você também não leu nenhuma resposta disponível antes de postarOs primeiros 10 diretórios com o maior número de arquivos.
fonte