Encontre o número de arquivos com uma extensão específica, em todos os subdiretórios
Pergunta
Existe uma maneira de encontrar o número de arquivos de um tipo específico sem precisar percorrer todos os resultados em um Directory.GetFiles() ou método semelhante?Estou procurando algo assim:
int ComponentCount = MagicFindFileCount(@"c:\windows\system32", "*.dll");
Eu sei que posso criar uma função recursiva para chamar Directory.GetFiles , mas seria muito mais limpo se pudesse fazer isso sem toda a iteração.
EDITAR: Se não for possível fazer isso sem recorrer e iterar, qual seria a melhor maneira de fazer isso?
Solução
Você deve usar o Directory.GetFiles (caminho, searchPattern, SearchOption) sobrecarga de Directory.GetFiles().
Path especifica o caminho, searchPattern especifica seus curingas (por exemplo, *, *.format) e SearchOption fornece a opção de incluir subdiretórios.
A propriedade Length da matriz de retorno desta pesquisa fornecerá a contagem de arquivos adequada para seu padrão e opção de pesquisa específicos:
string[] files = directory.GetFiles(@"c:\windows\system32", "*.dll", SearchOption.AllDirectories);
return files.Length;
EDITAR: Alternativamente você pode usar Método Directory.EnumerateFiles
return Directory.EnumerateFiles(@"c:\windows\system32", "*.dll", SearchOption.AllDirectories).Count();
Outras dicas
O método mais inteligente seria usar linq:
var fileCount = (from file in Directory.EnumerateFiles(@"H:\iPod_Control\Music", "*.mp3", SearchOption.AllDirectories)
select file).Count();
Você pode usar esta sobrecarga de GetFiles:
e este membro do SearchOption:
Todos os diretórios - Inclui o diretório atual e todos os subdiretos em uma operação de pesquisa.Esta opção inclui pontos reparados, como unidades montadas e links simbólicos na pesquisa.
GetFiles retorna uma matriz de strings para que você possa obter apenas o comprimento, que é o número de arquivos encontrados.
Eu estava procurando uma versão mais otimizada.Como não encontrei, resolvi codificá-lo e compartilhá-lo aqui:
public static int GetFileCount(string path, string searchPattern, SearchOption searchOption)
{
var fileCount = 0;
var fileIter = Directory.EnumerateFiles(path, searchPattern, searchOption);
foreach (var file in fileIter)
fileCount++;
return fileCount;
}
Todas as soluções que usam GetFiles/GetDirectories são meio lentas, pois todos esses objetos precisam ser criados.Usando a enumeração, ela não cria nenhum objeto temporário (FileInfo/DirectoryInfo).
veja comentários http://msdn.microsoft.com/en-us/library/dd383571.aspx Para maiores informações
Usando recursão, seu MagicFindFileCount ficaria assim:
private int MagicFindFileCount( string strDirectory, string strFilter ) {
int nFiles = Directory.GetFiles( strDirectory, strFilter ).Length;
foreach( String dir in Directory.GetDirectories( strDirectory ) ) {
nFiles += GetNumberOfFiles(dir, strFilter);
}
return nFiles;
}
No entanto A solução de Jon pode ser o melhor.
Eu tenho um aplicativo que gera contagens de diretórios e arquivos em um diretório pai.Alguns dos diretórios contêm milhares de subdiretórios com milhares de arquivos em cada um.Para fazer isso enquanto mantenho uma interface de usuário responsiva, faço o seguinte (enviando o caminho para ADirectoryPath foi selecionado método):
public class DirectoryFileCounter
{
int mDirectoriesToRead = 0;
// Pass this method the parent directory path
public void ADirectoryPathWasSelected(string path)
{
// create a task to do this in the background for responsive ui
// state is the path
Task.Factory.StartNew((state) =>
{
try
{
// Get the first layer of sub directories
this.AddCountFilesAndFolders(state.ToString())
}
catch // Add Handlers for exceptions
{}
}, path));
}
// This method is called recursively
private void AddCountFilesAndFolders(string path)
{
try
{
// Only doing the top directory to prevent an exception from stopping the entire recursion
var directories = Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly);
// calling class is tracking the count of directories
this.mDirectoriesToRead += directories.Count();
// get the child directories
// this uses an extension method to the IEnumerable<V> interface,
// which will run a function on an object. In this case 'd' is the
// collection of directories
directories.ActionOnEnumerable(d => AddCountFilesAndFolders(d));
}
catch // Add Handlers for exceptions
{
}
try
{
// count the files in the directory
this.mFilesToRead += Directory.EnumerateFiles(path).Count();
}
catch// Add Handlers for exceptions
{ }
}
}
// Extension class
public static class Extensions
{
// this runs the supplied method on each object in the supplied enumerable
public static void ActionOnEnumerable<V>(this IEnumerable<V> nodes,Action<V> doit)
{
foreach (var node in nodes)
{
doit(node);
}
}
}
Alguém tem que fazer a parte da iteração.
AFAIK, esse método ainda não existe no .NET, então acho que alguém tem que ser você.