Как рекурсивно перечислить все файлы в каталоге и дочерних каталогах на C#?Как рекурсивно перечислить все файлы в каталоге на C#?
ответ
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);
}
}
Этот метод не отображает файлы для начальный каталог, только его поддиректоры и ниже. Я бы переместил GetFiles вне GetDirectories – GONeale
Иногда не нужны файлы для исходного каталога, и в этом случае это идеально подходит для достаточно небольших структур. Для очень больших списков используйте что-то вроде решения Марка Гравелла: http://stackoverflow.com/a/929418/91189 –
@GONeale верна. Гораздо менее правдоподобно, чтобы пользователь не ожидал списка файлов корневого каталога ввода. Здесь вводится слово. Он был введен по причине. –
Обратите внимание, что в .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];
}
}
}
}
Как это будет работать, когда дело доходит до символических ссылок и т. П.? – soandos
Учитывайте пробелы как имя каталога => http://stackoverflow.com/q/5368054/2336304 – SerG
@soandos В рекурсивной точке перезаписи EnumerateFiles бросает IOException «Имя файла не может быть разрешено системой» – SerG
В .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);
Некоторые отличные ответы, но эти ответы не помогли решить мою проблему.
Как только возникает проблема с правами на доступ к папке: «Разрешение отклонено», код не работает. Это то, что я использовал, чтобы обойти проблему «Разрешение отказа»:
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); });
}
}
Надеюсь, это поможет другим.
В 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);
}
}
Вот мой угол на нем, на основе 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;
}
Вот версия не код 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;
}
Directory.GetFiles("C:\\", "*.*", SearchOption.AllDirectories)
Как избежать ошибки, если пользователь входа в систему не имеет доступа к некоторым папкам. –
@Romil Я не верю, что этот фрагмент кода пытается указать полную функциональность, только исходную функциональность, которую ищет OP. Спасибо, что поделились, Пескума! –
@kayleeFrye_onDeck, я ставлю только беспокойство в случае, если есть поднятый для любой папки при получении файлов. Из-за этой проблемы мы реализуем нашу пользовательскую рекурсивную функцию. –
Листинг файлов и папок для модели, пользовательской реализации.
Это создает полный список всех файлов и папок, начиная с вашего стартового каталога.
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);
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();
}
IEnumerable<string> GetFilesFromDir(string dir) =>
Directory.EnumerateFiles(dir).Concat(
Directory.EnumerateDirectories(dir)
.SelectMany(subdir => GetFilesFromDir(subdir)));
Простой и чистый раствор
/// <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);
}
}
}
Вы вручную делаете то, что DirectoryInfo.GetFiles() будет делать для вас из коробки - просто используйте перегрузку с помощью SearchOption.AllDirectories, и она сама перезапустит все. Так что это * сложное * решение. – philw
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)
{
}
}
Почему параметр 'files' является' ref'? Нет нужды. –
Короткий и простое решение
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);
Я предпочитаю использовать 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 расширением.
Где вы хотите, чтобы заполнить ? Если дерево ... вот пример http://www.dreamincode.net/code/snippet2591.htm –
Вы можете посмотреть [этот вопрос] (http://stackoverflow.com/questions/907307/ directory-structure-inside-treeview-vb /), где я представил образец кода, который использует рекурсию для визуализации структуры каталогов в TreeView. В большинстве случаев логика должна быть одинаковой. – Cerebrus
string [] filenames = Dire ctory.GetFiles (path, "*", SearchOption.AllDirectories) – Bruce