2009-05-30 3 views
229

Как рекурсивно перечислить все файлы в каталоге и дочерних каталогах на C#?Как рекурсивно перечислить все файлы в каталоге на C#?

+1

Где вы хотите, чтобы заполнить ? Если дерево ... вот пример http://www.dreamincode.net/code/snippet2591.htm –

+0

Вы можете посмотреть [этот вопрос] (http://stackoverflow.com/questions/907307/ directory-structure-inside-treeview-vb /), где я представил образец кода, который использует рекурсию для визуализации структуры каталогов в TreeView. В большинстве случаев логика должна быть одинаковой. – Cerebrus

+57

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

ответ

139

This статья охватывает все, что вам нужно. За исключением случаев, когда вы ищете файлы и сравниваете имена, просто распечатайте имена.

Он может быть изменен следующим образом:

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

Этот метод не отображает файлы для начальный каталог, только его поддиректоры и ниже. Я бы переместил GetFiles вне GetDirectories – GONeale

+1

Иногда не нужны файлы для исходного каталога, и в этом случае это идеально подходит для достаточно небольших структур. Для очень больших списков используйте что-то вроде решения Марка Гравелла: http://stackoverflow.com/a/929418/91189 –

+1

@GONeale верна. Гораздо менее правдоподобно, чтобы пользователь не ожидал списка файлов корневого каталога ввода. Здесь вводится слово. Он был введен по причине. –

339

Обратите внимание, что в .NET 4.0 есть (предположительно) итератор на основе (а не на основе массивов) файловых функций, построенных в:

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

На данный момент я бы использовал что-то вроде ниже; встроенный рекурсивный метод слишком легко ломается, если у вас нет доступа к одному субдиректору ...; использование Queue<string> позволяет избежать слишком большой рекурсии вызовов, а блок итератора позволяет избежать огромного массива.

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

Как это будет работать, когда дело доходит до символических ссылок и т. П.? – soandos

+0

Учитывайте пробелы как имя каталога => http://stackoverflow.com/q/5368054/2336304 – SerG

+1

@soandos В рекурсивной точке перезаписи EnumerateFiles бросает IOException «Имя файла не может быть разрешено системой» – SerG

11

В .NET 4.5, по крайней мере, есть такая версия, что гораздо короче и имеет дополнительный бонус оценки каких-либо критериев файлов для включения в список:

/// </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; 
     } 
    } 

Используйте как:

 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

Некоторые отличные ответы, но эти ответы не помогли решить мою проблему.

Как только возникает проблема с правами на доступ к папке: «Разрешение отклонено», код не работает. Это то, что я использовал, чтобы обойти проблему «Разрешение отказа»:

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); }); 
     } 
    } 

Надеюсь, это поможет другим.

4

В Framework 2.0 Вы можете использовать (это список файлов корневой папки, то лучше самый популярный ответ):

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

Вот мой угол на нем, на основе Hernaldo-х, если вам нужно найти файлы с названия определенного шаблона, такие как файлы XML, что где-то в их названии содержит определенную строку:

// 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

Вот версия не код B. Клея Шеннона статической для Excel-файлов:

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

Как избежать ошибки, если пользователь входа в систему не имеет доступа к некоторым папкам. –

+1

@Romil Я не верю, что этот фрагмент кода пытается указать полную функциональность, только исходную функциональность, которую ищет OP. Спасибо, что поделились, Пескума! –

+0

@kayleeFrye_onDeck, я ставлю только беспокойство в случае, если есть поднятый для любой папки при получении файлов. Из-за этой проблемы мы реализуем нашу пользовательскую рекурсивную функцию. –

0

Листинг файлов и папок для модели, пользовательской реализации.
Это создает полный список всех файлов и папок, начиная с вашего стартового каталога.

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 
    } 

Метод:

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; 
     } 

Использование:

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

Простой и чистый раствор

/// <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

Вы вручную делаете то, что DirectoryInfo.GetFiles() будет делать для вас из коробки - просто используйте перегрузку с помощью SearchOption.AllDirectories, и она сама перезапустит все. Так что это * сложное * решение. – 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

Почему параметр 'files' является' ref'? Нет нужды. –

0

Короткий и простое решение

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

Я предпочитаю использовать DirectoryInfo, потому что я могу получить, а не только строки 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(); 

Я делаю это в случае, если в будущем мне нужна будущая фильтрация .. основываясь на свойствах 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(); 

Я также могу прибегнуть к строкам, если потребуется. (И все еще будущее оборудована устройством для фильтров/где придаточного материал.

 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(); 

Обратите внимание, что «.» является действительным шаблоном поиска, если вы хотите FILER расширением.