it-roy-ru.com

Поиск файла в каталогах рекурсивно

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

Я понимаю, почему, поскольку первое, что он делает, это получает каталоги в корне, затем получает файлы, таким образом пропуская вызов GetFiles () в корне. Я пытался включить вызов GetFiles () до foreach, но результаты не такие, как я ожидал. 

public static ArrayList DirSearch(string sDir)
{
    try
    {
        foreach (string d in Directory.GetDirectories(sDir))
        {
            foreach (string f in Directory.GetFiles(d, "*.xml"))
            {
                string extension = Path.GetExtension(f);
                if (extension != null && (extension.Equals(".xml")))
                {
                fileList.Add(f);
                }
            }
            DirSearch(d);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    return fileList;
}

Моя структура каталогов выглядит примерно так:

RootDirectory
        test1.0.xml
            test1.1.xml
            test1.2.xml
  2ndLevDir
            test2.0.xml
            test2.1.xml
  3rdLevDir
               test3.0.xml
               test3.1.xml

Код возвращается:

test2.0.xml
test2.1.xml
test3.0.xml
test3.1.xml

Я хотел бы вернуть каждый файл, включая:

test1.0.xml
test1.1.xml
test1.2.xml

Не очень хорошо стих с рекурсией. Любые указатели будут с благодарностью.

46
Paul

Вы можете использовать это перегрузка Directory.GetFiles , которая ищет для вас подкаталоги, например:

string[] files = Directory.GetFiles(sDir, "*.xml", SearchOption.AllDirectories);

Так можно искать только одно расширение, но вы можете использовать что-то вроде:

var extensions = new List<string> { ".txt", ".xml" };
string[] files = Directory.GetFiles(sDir, "*.*", SearchOption.AllDirectories)
                    .Where(f => extensions.IndexOf(Path.GetExtension(f)) >= 0).ToArray();

выбрать файлы с необходимыми расширениями (например, чувствительно к регистру для расширения).


В некоторых случаях может быть желательно перечислить файлы с помощью метода Directory.EnumerateFiles :

foreach(string f in Directory.EnumerateFiles(sDir, "*.xml", SearchOption.AllDirectories))
{
    // do something
}

Консультируйтесь с документацией для исключений, которые могут быть выброшены, такие как UnauthorizedAccessException, если код выполняется под учетной записью, у которой нет соответствующих прав доступа.

87
Andrew Morton

Это возвращает все xml-файлы рекурсивно:

var allFiles = Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories);
46
Rango

Попробуйте следующий метод:

public static IEnumerable<string> GetXMLFiles(string directory)
{
    List<string> files = new List<string>();

    try
    {
        files.AddRange(Directory.GetFiles(directory, "*.xml", SearchOption.AllDirectories));
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

    return files;
}
3
Bernard

Вы создаете три списка вместо одного (вы не используете возвращаемое значение DirSearch(d)). Вы можете использовать список в качестве параметра для сохранения состояния:

static void Main(string[] args)
{
  var list = new List<string>();
  DirSearch(list, ".");

  foreach (var file in list)
  {
    Console.WriteLine(file);
  }
}

public static void DirSearch(List<string> files, string startDirectory)
{
  try
  {
    foreach (string file in Directory.GetFiles(startDirectory, "*.*"))
    {
      string extension = Path.GetExtension(file);

      if (extension != null)
      {
        files.Add(file);
      }
    }

    foreach (string directory in Directory.GetDirectories(startDirectory))
    {
      DirSearch(files, directory);
    }
  }
  catch (System.Exception e)
  {
    Console.WriteLine(e.Message);
  }
}
3
Gene

Вы должны иметь цикл над файлами либо до, либо после цикла над каталогами, но не должны быть вложены в него, как вы это сделали.

foreach (string f in Directory.GetFiles(d, "*.xml"))
{
    string extension = Path.GetExtension(f);
    if (extension != null && (extension.Equals(".xml")))
    {
        fileList.Add(f);
    }
} 

foreach (string d in Directory.GetDirectories(sDir))
{
    DirSearch(d);
}
3
Mark Byers

вы можете сделать что-то вроде этого: 

foreach (var file in Directory.GetFiles(MyFolder, "*.xml", SearchOption.AllDirectories))
        {
            // do something with this file
        }
2
damir

Вы захотите переместить цикл для файлов за пределы цикла для папок. Кроме того, вам нужно будет передавать структуру данных, содержащую коллекцию файлов, на каждый вызов метода. Таким образом, все файлы попадают в один список.

public static List<string> DirSearch(string sDir, List<string> files)
{
  foreach (string f in Directory.GetFiles(sDir, "*.xml"))
  {
    string extension = Path.GetExtension(f);
    if (extension != null && (extension.Equals(".xml")))
    {
      files.Add(f);
    }
  }
  foreach (string d in Directory.GetDirectories(sDir))
  {
    DirSearch(d, files);
  }
  return files;
}

Тогда назови это так.

List<string> files = DirSearch("c:\foo", new List<string>());

Обновление:

Что ж, без моего ведома, пока я не прочитаю другой ответ, встроенный механизм для этого уже существует. Я оставлю свой ответ на тот случай, если вам интересно узнать, как нужно изменить код, чтобы он работал.

1
Brian Gideon

Использование EnumerateFiles для получения файлов во вложенных каталогах. Используйте AllDirectories для просмотра каталогов.

using System;
using System.IO;

class Program
{
    static void Main()
    {
    // Call EnumerateFiles in a foreach-loop.
    foreach (string file in Directory.EnumerateFiles(@"c:\files",
        "*.xml",
        SearchOption.AllDirectories))
    {
        // Display file path.
        Console.WriteLine(file);
    }
    }
}
0
mercedes