2009-05-30 31 views
229

¿Cómo hacer una recursiva lista de todos los archivos en un directorio y directorios secundarios en C#?Cómo recursivamente enumerar todos los archivos en un directorio en C#?

+1

¿Dónde quiere poblar ? if tree ... aquí está el ejemplo http://www.dreamincode.net/code/snippet2591.htm –

+0

Es posible que desee consultar [esta pregunta] (http://stackoverflow.com/questions/907307/ directory-structure-within-treeview-vb /) donde he presentado un ejemplo de código que usa la recursividad para representar una estructura de directorios en un TreeView. La lógica debería ser la misma en la mayoría de los casos. – Cerebrus

+57

string [] filenames = Dire ctory.GetFiles (ruta, "*", SearchOption.AllDirectories) – Bruce

Respuesta

139

This artículo cubre todo lo que necesita. Excepto en lugar de buscar los archivos y comparar nombres, simplemente imprima los nombres.

Puede ser modificado así:

static void DirSearch(string sDir) 
{ 
    try 
    { 
     foreach (string d in Directory.GetDirectories(sDir)) 
     { 
      foreach (string f in Directory.GetFiles(d)) 
      { 
       Console.WriteLine(f); 
      } 
      DirSearch(d); 
     } 
    } 
    catch (System.Exception excpt) 
    { 
     Console.WriteLine(excpt.Message); 
    } 
} 
+59

Este método no muestra archivos para el directorio inicial, solo son subdirectores y más bajo. Me gustaría mover GetFiles fuera de GetDirectories – GONeale

+1

A veces uno no quiere los archivos para el directorio inicial, en cuyo caso esto es perfecto para estructuras razonablemente pequeñas. Para listas muy grandes, use algo como la solución de Marc Gravell: http://stackoverflow.com/a/929418/91189 –

+1

@GONeale es correcto. Es mucho menos plausible para un usuario no esperar la lista de archivos del directorio raíz de entrada. La entrada de palabra es la clave aquí. Ha sido ingresado por una razón. –

339

Nótese que en .NET 4.0 no son (supuestamente) (en vez de basadas en matrices) en funciones de archivo construidas a base de iterador:

foreach (string file in Directory.EnumerateFiles(
    path, "*.*", SearchOption.AllDirectories)) 
{ 
    Console.WriteLine(file); 
} 

Por el momento usaría algo como a continuación; el método recursivo incorporado se rompe demasiado fácilmente si no tiene acceso a un solo subdirectorio ...; el uso de Queue<string> evita demasiada recursividad de la pila de llamadas, y el bloque iterador nos evita tener una gran matriz.

static void Main() { 
    foreach (string file in GetFiles(SOME_PATH)) { 
     Console.WriteLine(file); 
    } 
} 

static IEnumerable<string> GetFiles(string path) { 
    Queue<string> queue = new Queue<string>(); 
    queue.Enqueue(path); 
    while (queue.Count > 0) { 
     path = queue.Dequeue(); 
     try { 
      foreach (string subDir in Directory.GetDirectories(path)) { 
       queue.Enqueue(subDir); 
      } 
     } 
     catch(Exception ex) { 
      Console.Error.WriteLine(ex); 
     } 
     string[] files = null; 
     try { 
      files = Directory.GetFiles(path); 
     } 
     catch (Exception ex) { 
      Console.Error.WriteLine(ex); 
     } 
     if (files != null) { 
      for(int i = 0 ; i < files.Length ; i++) { 
       yield return files[i]; 
      } 
     } 
    } 
} 
+1

¿Cómo funcionará esto cuando se trata de enlaces simbólicos y similares? – soandos

+0

Tenga en cuenta los espacios en blanco como el nombre del directorio => http://stackoverflow.com/q/5368054/2336304 – SerG

+1

@soandos En el punto de repetición recursivo EnumerateFiles lanza IOException "El nombre del archivo no puede ser resuelto por el sistema" – SerG

11

En .NET 4.5, al menos, hay una versión que es mucho más corto y tiene la ventaja añadida de evaluar los criterios de archivos para su inclusión en la lista:

/// </remarks> 
    public static IEnumerable<string> GetAllFiles(string path, Func<FileInfo, bool> checkFile = null) 
    { 
     string mask = Path.GetFileName(path); 
     if (string.IsNullOrEmpty(mask)) 
      mask = "*.*"; 
     path = Path.GetDirectoryName(path); 
     string[] files = Directory.GetFiles(path, mask, SearchOption.AllDirectories); 
     foreach (string file in files) 
     { 
      if (checkFile == null || checkFile(new FileInfo(file))) 
       yield return file; 
     } 
    } 

Uso como:

 string folder = Config.TestInput(); 
     string mask = folder + "*.*"; 
     var list = UT.GetAllFiles(mask, (info) => Path.GetExtension(info.Name) == ".html").ToList(); 
     Assert.AreNotEqual(0, list.Count); 
     var lastQuarter = DateTime.Now.AddMonths(-3); 
     list = UT.GetAllFiles(mask, (info) => info.CreationTime >= lastQuarter).ToList(); 
     Assert.AreNotEqual(0, list.Count); 
3

Algunas respuestas excelentes, pero estas respuestas no solucionaron mi problema.

En cuanto surge un problema de permiso de carpeta: "Permiso denegado", el código falla. Esto es lo que solía hacer con el tema "Permiso denegado":

private int counter = 0; 

    private string[] MyDirectories = Directory.GetDirectories("C:\\"); 

    private void ScanButton_Click(object sender, EventArgs e) 
    { 
     Thread MonitorSpeech = new Thread(() => ScanFiles()); 
     MonitorSpeech.Start(); 
    } 

    private void ScanFiles() 
    { 
     string CurrentDirectory = string.Empty; 

     while (counter < MyDirectories.Length) 
     { 
      try 
      { 
       GetDirectories(); 
       CurrentDirectory = MyDirectories[counter++]; 
      } 
      catch 
      { 
       if (!this.IsDisposed) 
       { 
        listBox1.Invoke((MethodInvoker)delegate { listBox1.Items.Add("Access Denied to : " + CurrentDirectory); }); 
       } 
      } 
     } 
    } 

    private void GetDirectories() 
    { 
     foreach (string directory in MyDirectories) 
     { 
      GetFiles(directory); 
     } 
    } 

    private void GetFiles(string directory) 
    { 
     try 
     { 
      foreach (string file in Directory.GetFiles(directory, "*")) 
      { 
       listBox1.Invoke((MethodInvoker)delegate { listBox1.Items.Add(file); }); 
      } 
     } 
     catch 
     { 
      listBox1.Invoke((MethodInvoker)delegate { listBox1.Items.Add("Access Denied to : " + directory); }); 
     } 
    } 

Espero que esto ayude a los demás.

4

En Marco 2.0 se puede utilizar (archivos a esta lista de carpeta raíz, lo mejor es la respuesta más popular):

static void DirSearch(string dir) 
{ 
    try 
    { 
     foreach (string f in Directory.GetFiles(dir)) 
      Console.WriteLine(f); 
     foreach (string d in Directory.GetDirectories(dir)) 
     { 
      Console.WriteLine(d); 
      DirSearch(d); 
     } 

    } 
    catch (System.Exception ex) 
    { 
     Console.WriteLine(ex.Message); 
    } 
} 
0

Aquí está mi punto de vista en él, sobre la base de Hernaldo de, si usted necesita para encontrar archivos con nombres de un cierto patrón, como archivos XML que en algún lugar de su nombre contienen una cadena en particular:

// call this like so: GetXMLFiles("Platypus", "C:\\"); 
public static List<string> GetXMLFiles(string fileType, string dir) 
{ 
    string dirName = dir; 
    var fileNames = new List<String>(); 
    try 
    { 
     foreach (string f in Directory.GetFiles(dirName)) 
     { 
      if ((f.Contains(fileType)) && (f.Contains(".XML"))) 
      { 
       fileNames.Add(f); 
      } 
     } 
     foreach (string d in Directory.GetDirectories(dirName)) 
     { 
      GetXMLFiles(fileType, d); 
     } 
    } 
    catch (Exception ex) 
    { 
     MessageBox.Show(ex.Message); 
    } 
    return fileNames; 
} 
-1

Aquí es una versión de código de arcilla B. Shannon no estática de Excel-archivos:

class ExcelSearcher 
{ 
    private List<string> _fileNames; 

    public ExcelSearcher(List<string> filenames) 
    { 
     _fileNames = filenames; 
    } 
    public List<string> GetExcelFiles(string dir, List<string> filenames = null) 
    { 

     string dirName = dir; 
     var dirNames = new List<string>(); 
     if (filenames != null) 
     { 
      _fileNames.Concat(filenames); 
     } 
     try 
     { 
      foreach (string f in Directory.GetFiles(dirName)) 
      { 
       if (f.ToLower().EndsWith(".xls") || f.ToLower().EndsWith(".xlsx")) 
       { 
        _fileNames.Add(f); 
       } 
      } 
      dirNames = Directory.GetDirectories(dirName).ToList(); 
      foreach (string d in dirNames) 
      { 
       GetExcelFiles(d, _fileNames); 
      } 
     } 
     catch (Exception ex) 
     { 
      //Bam 
     } 
     return _fileNames; 
    } 
64
Directory.GetFiles("C:\\", "*.*", SearchOption.AllDirectories) 
+2

Cómo evitar el error si el usuario de inicio de sesión no tiene acceso en algunas de las carpetas. –

+1

@Romil No creo que este fragmento de código intente indicar la funcionalidad completa, solo la funcionalidad sin procesar que el OP estaba buscando. Gracias por compartir, Pescuma! –

+0

@kayleeFrye_onDeck, puse solo una preocupación en caso de que haya un problema para cualquiera de la carpeta al obtener archivos. Debido a esta preocupación, implementamos nuestra función recursiva personalizada. –

0

Listado de archivos y carpetas para modelar, implementación personalizada.
Esto crea una lista completa de todos los archivos y carpetas a partir de su directorio de inicio.

public class DirOrFileModel 
    { 
     #region Private Members 

     private string _name; 
     private string _location; 
     private EntryType _entryType; 

     #endregion 

     #region Bindings 

     public string Name 
     { 
      get { return _name; } 
      set 
      { 
       if (value == _name) return; 
       _name = value; 
      } 
     } 

     public string Location 
     { 
      get { return _location; } 
      set 
      { 
       if (value == _location) return; 
       _location = value; 
      } 
     } 

     public EntryType EntryType 
     { 
      get { return _entryType; } 
      set 
      { 
       if (value == _entryType) return; 
       _entryType = value; 
      } 
     } 

     public ObservableCollection<DirOrFileModel> Entries { get; set; } 

     #endregion 

     #region Constructor 

     public DirOrFileModel() 
     { 
      Entries = new ObservableCollection<DirOrFileModel>(); 
     } 

     #endregion 
    } 

    public enum EntryType 
    { 
     Directory = 0, 
     File = 1 
    } 

Método:

static DirOrFileModel DirSearch(DirOrFileModel startDir) 
     { 
      var currentDir = startDir; 
      try 
      { 
       foreach (string d in Directory.GetDirectories(currentDir.Location)) 
       { 
        var newDir = new DirOrFileModel 
        { 
         EntryType = EntryType.Directory, 
         Location = d, 
         Name = Path.GetFileName(d) 
        }; 
        currentDir.Entries.Add(newDir); 

        DirSearch(newDir); 
       } 

       foreach (string f in Directory.GetFiles(currentDir.Location)) 
       { 
        var newFile = new DirOrFileModel 
        { 
         EntryType = EntryType.File, 
         Location = f, 
         Name = Path.GetFileNameWithoutExtension(f) 
        }; 
        currentDir.Entries.Add(newFile); 
       } 

      } 
      catch (Exception excpt) 
      { 
       Console.WriteLine(excpt.Message); 
      } 
      return startDir; 
     } 

Uso:

var dir = new DirOrFileModel 
      { 
       Name = "C", 
       Location = @"C:\", 
       EntryType = EntryType.Directory 
      }; 

      dir = DirSearch(dir); 
0
static void Main(string[] args) 
     { 
      string[] array1 = Directory.GetFiles(@"D:\"); 
      string[] array2 = System.IO.Directory.GetDirectories(@"D:\"); 
      Console.WriteLine("--- Files: ---"); 
      foreach (string name in array1) 
      { 
       Console.WriteLine(name); 
      } 
      foreach (string name in array2) 
      { 
       Console.WriteLine(name); 
      } 
        Console.ReadLine(); 
     } 
7
IEnumerable<string> GetFilesFromDir(string dir) => 
Directory.EnumerateFiles(dir).Concat(
Directory.EnumerateDirectories(dir) 
      .SelectMany(subdir => GetFilesFromDir(subdir))); 
3

Una solución simple y limpio

/// <summary> 
/// Scans a folder and all of its subfolders recursively, and updates the List of files 
/// </summary> 
/// <param name="sFullPath">Full path of the folder</param> 
/// <param name="files">The list, where the output is expected</param> 
internal static void EnumerateFiles(string sFullPath, List<FileInfo> fileInfoList) 
{ 
    try 
    { 
     DirectoryInfo di = new DirectoryInfo(sFullPath); 
     FileInfo[] files = di.GetFiles(); 

     foreach (FileInfo file in files) 
      fileInfoList.Add(file); 

     //Scan recursively 
     DirectoryInfo[] dirs = di.GetDirectories(); 
     if (dirs == null || dirs.Length < 1) 
      return; 
     foreach (DirectoryInfo dir in dirs) 
      EnumerateFiles(dir.FullName, fileInfoList); 

    } 
    catch (Exception ex) 
    { 
     Logger.Write("Exception in Helper.EnumerateFiles", ex); 
    } 
} 

}

+0

Estás haciendo manualmente lo que DirectoryInfo.GetFiles() hará por ti de la caja: simplemente usa la sobrecarga con SearchOption.AllDirectories y se volverá a generar por sí solo. Entonces esa es una * solución * complicada. – philw

0
private void GetFiles(DirectoryInfo dir, ref List<FileInfo> files) 
{ 
    try 
    { 
     files.AddRange(dir.GetFiles()); 
     DirectoryInfo[] dirs = dir.GetDirectories(); 
     foreach (var d in dirs) 
     { 
      GetFiles(d, ref files); 
     } 
    } 
    catch (Exception e) 
    { 

    } 
} 
+0

¿Por qué el parámetro 'files' es' ref'? No hay necesidad. –

0

solución a corto y simple

string dir = @"D:\PATH"; 

DateTime from_date = DateTime.Now.Date; 
DateTime to_date = DateTime.Now.Date.AddHours(23); 
var files = Directory.EnumerateFiles(dir, "*.*",SearchOption.AllDirectories).Select(i=>new FileInfo(i)) 
.Where(file=>file.LastWriteTime >= from_date && file.LastWriteTime <= to_date); 
foreach(var fl in files) 
    Console.WriteLine(fl.FullName); 
0

Yo prefiero usar DirectoryInfo porque puedo conseguir, no sólo cadenas de FileInfo.

 string baseFolder = @"C:\temp"; 
     DirectoryInfo di = new DirectoryInfo(baseFolder); 

     string searchPattern = "*.xml"; 

     ICollection<FileInfo> matchingFileInfos = di.GetFiles(searchPattern, SearchOption.AllDirectories) 
      .Select(x => x) 
      .ToList(); 

Lo hago en caso de que en el futuro necesite un futuro filtrado ... en función de las propiedades de FileInfo.

 string baseFolder = @"C:\temp"; 
     DirectoryInfo di = new DirectoryInfo(baseFolder); 

     string searchPattern = "*.xml"; 

     ICollection<FileInfo> matchingFileInfos = di.GetFiles(searchPattern, SearchOption.AllDirectories) 
      .Where(x => x.LastWriteTimeUtc < DateTimeOffset.Now) 
      .Select(x => x) 
      .ToList(); 

También puedo recurrir a las cadenas si es necesario. (Y todavía lo soy prueba de futuro para los filtros/cláusula-where cosas.

 string baseFolder = @"C:\temp"; 
     DirectoryInfo di = new DirectoryInfo(baseFolder); 

     string searchPattern = "*.xml"; 

     ICollection<string> matchingFileNames = di.GetFiles(searchPattern, SearchOption.AllDirectories) 
      .Select(x => x.FullName) 
      .ToList(); 

Tenga en cuenta que "" es un patrón de búsqueda válida si quieres Filer por extensión.

Cuestiones relacionadas