Список всех файлов и каталогов в каталоге + подкаталогах

110

Я хочу перечислить все файлы и каталоги, содержащиеся в каталоге и подкаталогах этого каталога. Если я выберу C: \ в качестве каталога, программа получит все имена всех файлов и папок на жестком диске, к которым у нее есть доступ.

Список может выглядеть так

fd \ 1.txt
fd \ 2.txt
fd \ a \
fd \ b \
fd \ a \ 1.txt
fd \ a \ 2.txt
fd \ a \ a \
fd \ a \ b \
fd \ b \ 1.txt
fd \ b \ 2.txt
fd \ b \ a
fd \ b \ b
fd \ a \ a \ 1.txt
fd \ a \ a \ a \
fd \ a \ b \ 1.txt
fd \ a \ b \ a
fd \ b \ a \ 1.txt
fd \ b \ a \ a \
fd \ b \ b \ 1.txt
fd \ b \ b \ a
derp_in_mouth
источник
Найдите в пространстве имен System.IO классы и методы, которые могут вам помочь.
Lucero
Проверьте этот вопрос и оставьте ту часть, где он соответствует шаблону.
dasblinkenlight 08

Ответы:

194
string[] allfiles = Directory.GetFiles("path/to/dir", "*.*", SearchOption.AllDirectories);

где *.*шаблон для сопоставления файлов

Если Справочник также нужен, вы можете сделать это так:

 foreach (var file in allfiles){
     FileInfo info = new FileInfo(file);
 // Do something with the Folder or just add them to a list via nameoflist.add();
 }
Руслан Ф.
источник
1
Не будет работать ... Lsit<>класс? Что возвращает GetFiles? А как насчет имен каталогов, которые также были запрошены?
Lucero
1
GetFilesМетод возвращает массив строк.
Guffa
на самом деле ... вы правы ... Я изучаю Qt около 2 дней назад и немного ошибся
Руслан Ф.
Это может сработать, но часто возникает ошибка UnauthorizedAccessException. Как искать только в каталогах, к которым у него есть доступ?
derp_in_mouth 08
это означает, что в вашей системе этому приложению недостаточно разрешений
Руслан Ф.
50

Directory.GetFileSystemEntriesсуществует в .NET 4.0+ и возвращает как файлы, так и каталоги. Назовите это так:

string[] entries = Directory.GetFileSystemEntries(path, "*", SearchOption.AllDirectories);

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

Аластер Мо
источник
3
Это, безусловно, лучший ответ здесь. Он объединяет все файлы и папки в одну строку кода, чего не делают другие.
Стив Смит,
15

Используйте GetDirectoriesи GetFilesметоды , чтобы получить файлы и папки.

Используйте также, чтобы получить папки и файлы во вложенных папках.SearchOption AllDirectories

Гуффа
источник
Используйте Substring, чтобы отрезать левую часть имени. :)
Lucero
@Lucero Как и зачем вы это сделали? Pathпредлагает более надежные методы.
Gusdor
@Gusdor Не стесняйтесь предложить более подходящий способ использования Pathдля удаления фиксированной левой части пути, например, `C:` в приведенном примере.
Lucero
@Lucero мой комментарий был плохо сформулирован. «Использовать подстроку» мало что мне говорит, и мне пришлось застрять в linqpad, чтобы найти хорошее решение. Например, что это за параметр? Собираетесь ли вы path.SubString(2)наивно удалить букву диска и двоеточие? Что, если каталог является сетевым ресурсом? Я предлагаю это Pathкак надежный метод, потому что он может принести массу пользы в этой области. В этом случае вы можете писать filePath.Substring(Path.GetPathRoot(filePath).Length). Да, здесь используется подстрока, поскольку она наиболее краткая.
Gusdor
11
public static void DirectorySearch(string dir)
{
    try
    {
        foreach (string f in Directory.GetFiles(dir))
        {
            Console.WriteLine(Path.GetFileName(f));
        }
        foreach (string d in Directory.GetDirectories(dir))
        {
            Console.WriteLine(Path.GetFileName(d));
            DirectorySearch(d);
        }
    }
    catch (System.Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}
Эван Дангол
источник
3
Ваш ответ улучшился бы, если бы вы могли добавить небольшое объяснение того, что делает код.
Alex
Он рекурсивно проходит через каталог и печатает имена файлов или имена каталогов. Для каждого внутреннего каталога он вызывает одну и ту же функцию. Для получения дополнительной информации: stackoverflow.com/questions/929276/…
I.Step
3

Боюсь, GetFilesметод возвращает список файлов, а не каталоги. Список в вопросе подсказывает мне, что результат должен включать и папки. Если вам нужен более индивидуальный список, вы можете попробовать позвонить GetFilesи GetDirectoriesрекурсивно. Попробуй это:

List<string> AllFiles = new List<string>();
void ParsePath(string path)
{
    string[] SubDirs = Directory.GetDirectories(path);
    AllFiles.AddRange(SubDirs);
    AllFiles.AddRange(Directory.GetFiles(path));
    foreach (string subdir in SubDirs)
        ParsePath(subdir);
}

Совет: Вы можете использовать FileInfoи DirectoryInfoклассы , если вам нужно проверить любой атрибут конкретного.

Кришна Шарма
источник
2

Некоторая улучшенная версия с максимальным уровнем для перехода в каталог и возможностью исключения папок:

using System;
using System.IO;

class MainClass {
  public static void Main (string[] args) {

    var dir = @"C:\directory\to\print";
    PrintDirectoryTree(dir, 2, new string[] {"folder3"});
  }


  public static void PrintDirectoryTree(string directory, int lvl, string[] excludedFolders = null, string lvlSeperator = "")
  {
    excludedFolders = excludedFolders ?? new string[0];

    foreach (string f in Directory.GetFiles(directory))
    {
        Console.WriteLine(lvlSeperator+Path.GetFileName(f));
    } 

    foreach (string d in Directory.GetDirectories(directory))
    {
        Console.WriteLine(lvlSeperator + "-" + Path.GetFileName(d));

        if(lvl > 0 && Array.IndexOf(excludedFolders, Path.GetFileName(d)) < 0)
        {
          PrintDirectoryTree(d, lvl-1, excludedFolders, lvlSeperator+"  ");
        }
    }
  }
}

входной каталог:

-folder1
  file1.txt
  -folder2
    file2.txt
    -folder5
      file6.txt
  -folder3
    file3.txt
  -folder4
    file4.txt
    file5.txt

вывод функции (содержимое папки 5 исключено из-за ограничения lvl, а содержимое папки 3 исключено, потому что она находится в массиве excludedFolders):

-folder1
  file1.txt
  -folder2
    file2.txt
    -folder5
  -folder3
  -folder4
    file4.txt
    file5.txt
мозговой поток98
источник
1

Вы можете использовать FindFirstFile, который возвращает дескриптор, а затем рекурсивно вызывает функцию, которая вызывает FindNextFile. Это хороший подход, поскольку указанная структура будет заполнена различными данными, такими как AlternativeName, lastTmeCreated, modified, атрибуты и т. Д.

Но поскольку вы используете .net framework, вам придется войти в неуправляемую область.

Резниченку Богдан
источник
0

Если у вас нет доступа к подпапке внутри дерева каталогов, Directory.GetFiles останавливает и генерирует исключение, которое приводит к нулевому значению в принимающей строке [].

Вот этот ответ https://stackoverflow.com/a/38959208/6310707

Он управляет исключением внутри цикла и продолжает работу, пока не будет пройдена вся папка.

Шубхам
источник
0

логичный и упорядоченный способ:

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

namespace DirLister
{
class Program
{
    public static void Main(string[] args)
    {
        //with reflection I get the directory from where this program is running, thus listing all files from there and all subdirectories
        string[] st = FindFileDir(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
        using ( StreamWriter sw = new StreamWriter("listing.txt", false ) )
        {
            foreach(string s in st)
            {
                //I write what I found in a text file
                sw.WriteLine(s);
            }
        }
    }

    private static string[] FindFileDir(string beginpath)
    {
        List<string> findlist = new List<string>();

        /* I begin a recursion, following the order:
         * - Insert all the files in the current directory with the recursion
         * - Insert all subdirectories in the list and rebegin the recursion from there until the end
         */
        RecurseFind( beginpath, findlist );

        return findlist.ToArray();
    }

    private static void RecurseFind( string path, List<string> list )
    {
        string[] fl = Directory.GetFiles(path);
        string[] dl = Directory.GetDirectories(path);
        if ( fl.Length>0 || dl.Length>0 )
        {
            //I begin with the files, and store all of them in the list
            foreach(string s in fl)
                list.Add(s);
            //I then add the directory and recurse that directory, the process will repeat until there are no more files and directories to recurse
            foreach(string s in dl)
            {
                list.Add(s);
                RecurseFind(s, list);
            }
        }
    }
}
}
Саша
источник
Не могли бы вы дать объяснение или встроенные комментарии, что делает ваш код?
MarthyM
конечно, сделал это, но это должно быть понятно, это простая циклическая рекурсия по всем каталогам и файлам
Саша
0

В следующем примере показан самый быстрый (не распараллеленный) способ перечисления файлов и подпапок в дереве каталогов, обрабатывающих исключения. Было бы быстрее использовать Directory.EnumerateDirectories с помощью SearchOption.AllDirectories для перечисления всех каталогов, но этот метод завершится ошибкой, если попадет в UnauthorizedAccessException или PathTooLongException.

Использует общий тип коллекции Stack, который является стеком "последний пришел - первым вышел" (LIFO) и не использует рекурсию. Из https://msdn.microsoft.com/en-us/library/bb513869.aspx , позволяет перечислить все подкаталоги и файлы и эффективно справиться с этими исключениями.

    public class StackBasedIteration
{
    static void Main(string[] args)
    {
        // Specify the starting folder on the command line, or in 
        // Visual Studio in the Project > Properties > Debug pane.
        TraverseTree(args[0]);

        Console.WriteLine("Press any key");
        Console.ReadKey();
    }

    public static void TraverseTree(string root)
    {
        // Data structure to hold names of subfolders to be
        // examined for files.
        Stack<string> dirs = new Stack<string>(20);

        if (!System.IO.Directory.Exists(root))
        {
            throw new ArgumentException();
        }
        dirs.Push(root);

        while (dirs.Count > 0)
        {
            string currentDir = dirs.Pop();
            string[] subDirs;
            try
            {
                subDirs = System.IO.Directory.EnumerateDirectories(currentDir); //TopDirectoryOnly
            }
            // An UnauthorizedAccessException exception will be thrown if we do not have
            // discovery permission on a folder or file. It may or may not be acceptable 
            // to ignore the exception and continue enumerating the remaining files and 
            // folders. It is also possible (but unlikely) that a DirectoryNotFound exception 
            // will be raised. This will happen if currentDir has been deleted by
            // another application or thread after our call to Directory.Exists. The 
            // choice of which exceptions to catch depends entirely on the specific task 
            // you are intending to perform and also on how much you know with certainty 
            // about the systems on which this code will run.
            catch (UnauthorizedAccessException e)
            {                    
                Console.WriteLine(e.Message);
                continue;
            }
            catch (System.IO.DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }

            string[] files = null;
            try
            {
                files = System.IO.Directory.EnumerateFiles(currentDir);
            }

            catch (UnauthorizedAccessException e)
            {

                Console.WriteLine(e.Message);
                continue;
            }

            catch (System.IO.DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            // Perform the required action on each file here.
            // Modify this block to perform your required task.
            foreach (string file in files)
            {
                try
                {
                    // Perform whatever action is required in your scenario.
                    System.IO.FileInfo fi = new System.IO.FileInfo(file);
                    Console.WriteLine("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime);
                }
                catch (System.IO.FileNotFoundException e)
                {
                    // If file was deleted by a separate application
                    //  or thread since the call to TraverseTree()
                    // then just continue.
                    Console.WriteLine(e.Message);
                    continue;
                }
                catch (UnauthorizedAccessException e)
                {                    
                    Console.WriteLine(e.Message);
                    continue;
                }
            }

            // Push the subdirectories onto the stack for traversal.
            // This could also be done before handing the files.
            foreach (string str in subDirs)
                dirs.Push(str);
        }
    }
}
Маркус
источник
Используете Задачи для большого количества файлов и каталогов?
PreguntonCojoneroCabrón
msdn.microsoft.com/en-us/library/ff477033(v=vs.110).aspx - это версия вышеупомянутого решения с параллельной потоковой передачей, использующая коллекцию стека и быстрее.
Маркус
0

Я использую следующий код с формой с двумя кнопками, одна для выхода, а другая для запуска. Диалог браузера папок и диалог сохранения файла. Код приведен ниже и работает в моей системе Windows10 (64):

using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Directory_List
{

    public partial class Form1 : Form
    {
        public string MyPath = "";
        public string MyFileName = "";
        public string str = "";

        public Form1()
        {
            InitializeComponent();
        }    
        private void cmdQuit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }    
        private void cmdGetDirectory_Click(object sender, EventArgs e)
        {
            folderBrowserDialog1.ShowDialog();
            MyPath = folderBrowserDialog1.SelectedPath;    
            saveFileDialog1.ShowDialog();
            MyFileName = saveFileDialog1.FileName;    
            str = "Folder = " + MyPath + "\r\n\r\n\r\n";    
            DirectorySearch(MyPath);    
            var result = MessageBox.Show("Directory saved to Disk!", "", MessageBoxButtons.OK);
                Application.Exit();    
        }    
        public void DirectorySearch(string dir)
        {
                try
            {
                foreach (string f in Directory.GetFiles(dir))
                {
                    str = str + dir + "\\" + (Path.GetFileName(f)) + "\r\n";
                }    
                foreach (string d in Directory.GetDirectories(dir, "*"))
                {

                    DirectorySearch(d);
                }
                        System.IO.File.WriteAllText(MyFileName, str);

            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}
Гарри
источник
0

При этом вы можете просто запустить их и выбрать подпапку при запуске консоли.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using data.Patcher; // The patcher XML
namespace PatchBuilder
{
class Program
{
    static void Main(string[] args)
    {
        string patchDir;
        if (args.Length == 0)
        {
            Console.WriteLine("Give the patch directory in argument");
            patchDir = Console.ReadLine();
        }
        else
        {
            patchDir = args[0];
        }

        if (File.Exists(Path.Combine(patchDir, "patch.xml")))
            File.Delete(Path.Combine(patchDir, "patch.xml"));

        var files = Directory.EnumerateFiles(patchDir, "*", SearchOption.AllDirectories).OrderBy(p => p).ToList();

        foreach (var file in files.Where(file => file.StartsWith("patch\\Resources")).ToArray())
        {
            files.Remove(file);
            files.Add(file);
        }

        var tasks = new List<MetaFileEntry>();
        using (var md5Hasher = MD5.Create())
        {
            for (int i = 0; i < files.Count; i++)
            {
                var file = files[i];

                if ((File.GetAttributes(file) & FileAttributes.Hidden) != 0)
                    continue;

                var content = File.ReadAllBytes(file);
                var md5Hasher2 = MD5.Create();

                var task =
                    new MetaFileEntry
                    {
                        LocalURL = GetRelativePath(file, patchDir + "\\"),
                        RelativeURL = GetRelativePath(file, patchDir + "\\"),
                        FileMD5 = Convert.ToBase64String(md5Hasher2.ComputeHash(content)),
                        FileSize = content.Length,
                    };

                md5Hasher2.Dispose();

                var pathBytes = Encoding.UTF8.GetBytes(task.LocalURL.ToLower());
                md5Hasher.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0);
                if (i == files.Count - 1)
                    md5Hasher.TransformFinalBlock(content, 0, content.Length);
                else
                    md5Hasher.TransformBlock(content, 0, content.Length, content, 0);

                tasks.Add(task);
                Console.WriteLine(@"Add " + task.RelativeURL);
            }

            var patch = new MetaFile
            {
                Tasks = tasks.ToArray(),
                FolderChecksum = BitConverter.ToString(md5Hasher.Hash).Replace("-", "").ToLower(),
            };


            //XmlUtils.Serialize(Path.Combine(patchDir, "patch.xml"), patch);
            Console.WriteLine(@"Created Patch in {0} !", Path.Combine(patchDir, "patch.xml"));
        }

        Console.Read();
    }

    static string GetRelativePath(string fullPath, string relativeTo)
    {
        var foldersSplitted = fullPath.Split(new[] { relativeTo.Replace("/", "\\").Replace("\\\\", "\\") }, StringSplitOptions.RemoveEmptyEntries); // cut the source path and the "rest" of the path

        return foldersSplitted.Length > 0 ? foldersSplitted.Last() : ""; // return the "rest"
    }
}
}

и это патчар для экспорта XML

using System.Xml.Serialization;

namespace data.Patcher
{
    public class MetaFile
    {

        [XmlArray("Tasks")]
        public MetaFileEntry[] Tasks
        {
            get;
            set;
        }

        [XmlAttribute("checksum")]
        public string FolderChecksum
        {
            get;
            set;
        }
    }
}
Smar ts
источник
-1
using System.IO;
using System.Text;
string[] filePaths = Directory.GetFiles(@"path", "*.*", SearchOption.AllDirectories);
ааа
источник
Ваш ответ не добавляет ничего нового к уже существующему ответу, получившему наибольшее количество голосов.
локаль по умолчанию
1
Это также неправильно, поскольку это не возвращает никаких каталогов (как указано в вопросе), а только фактические файлы.
Алистер Мо
-1

Немного просто и медленно, но работает !! если вы не указываете путь к файлу, в основном используйте «fixPath», это просто пример .... вы можете искать нужный тип файла, какой хотите, я сделал ошибку, когда выбрал имя списка, потому что «временный список файлов» - это список искомых файлов так что продолжайте .... и "errorList" говорит сам за себя

 static public void Search(string path, string fileType, List<string> temporaryFileList, List<string> errorList)
    {

        List<string> temporaryDirectories = new List<string>();

        //string fix = @"C:\Users\" + Environment.UserName + @"\";
        string fix = @"C:\";
        string folders = "";
        //Alap útvonal megadása 
        if (path.Length != 0)
        { folders = path; }
        else { path = fix; }

        int j = 0;
        int equals = 0;
        bool end = true;

        do
        {

            equals = j;
            int k = 0;

            try
            {

                int foldersNumber = 
                Directory.GetDirectories(folders).Count();
                int fileNumber = Directory.GetFiles(folders).Count();

                if ((foldersNumber != 0 || fileNumber != 0) && equals == j)
                {

                    for (int i = k; k < 
                    Directory.GetDirectories(folders).Length;)
                    {

             temporaryDirectories.Add(Directory.GetDirectories(folders)[k]);
                        k++;
                    }

                    if (temporaryDirectories.Count == j)
                    {
                        end = false;
                        break;
                    }
                    foreach (string files in Directory.GetFiles(folders))
                    {
                        if (files != string.Empty)
                        {
                            if (fileType.Length == 0)
                            {
                                temporaryDirectories.Add(files);
                            }
                            else
                            {

                                if (files.Contains(fileType))
                                {
                                    temporaryDirectories.Add(files);

                                }
                            }
                        }
                        else
                        {
                            break;
                        }
                    }

                }

                equals++;

                for (int i = j; i < temporaryDirectories.Count;)
                {
                    folders = temporaryDirectories[i];
                    j++;
                    break;
                }

            }
            catch (Exception ex)
            {
                errorList.Add(folders);

                for (int i = j; i < temporaryDirectories.Count;)
                {
                    folders = temporaryDirectories[i];
                    j++;
                    break;
                }
            }
        } while (end);
    }
Пека
источник
-1

Создать список строк

    public static List<string> HTMLFiles = new List<string>();

 private void Form1_Load(object sender, EventArgs e)
        {

     HTMLFiles.AddRange(Directory.GetFiles(@"C:\DataBase", "*.txt"));
            foreach (var item in HTMLFiles)
            {
                MessageBox.Show(item);
            }

}
رضا جون
источник
Подкаталоги не попадают.
TidyDev