Як рекурсивно перелічити всі файли в каталозі та дочірні каталоги в C #?
Як рекурсивно перелічити всі файли в каталозі та дочірні каталоги в C #?
Відповіді:
Ця стаття охоплює все, що вам потрібно. За винятком пошуку файлів та порівняння імен, просто роздрукуйте імена.
Його можна змінити так:
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);
}
}
Додано барлопом
GONeale зазначає, що вищевказане не перераховує файли в поточній директорії, і пропонує розмістити частину файлу, що містить список, поза тією частиною, яка отримує каталоги. Наступне зробить це. Вона також включає в себе рядок Writeline, який ви можете коментувати, що допомагає простежити, де ви перебуваєте в рекурсії, що може допомогти показати дзвінки, щоб допомогти показати, як працює рекурсія.
DirSearch_ex3("c:\\aaa");
static void DirSearch_ex3(string sDir)
{
//Console.WriteLine("DirSearch..(" + sDir + ")");
try
{
Console.WriteLine(sDir);
foreach (string f in Directory.GetFiles(sDir))
{
Console.WriteLine(f);
}
foreach (string d in Directory.GetDirectories(sDir))
{
DirSearch_ex3(d);
}
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
}
Зауважте, що в .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];
}
}
}
}
*.*
включає також файли без розширення файлу: Так, це перевірено хвилину тому.
using System.IO;
Console
вам потрібно буде додати, using System;
але оскільки IDE може додати всі необхідні для васusing
директиви (ctrl +.), І оскільки ми тут не використовуємо нічого екзотичного, зазвичай не включати їх. Чорт, вам також знадобиться визначення тощо. Просто class
Directory.GetFiles("C:\\", "*.*", SearchOption.AllDirectories)
Принаймні, у .NET 4.5 є ця версія, яка набагато коротша і має додатковий бонус при оцінці будь-яких файлових критеріїв для включення до списку:
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;
}
}
Використовуйте так:
var list = GetAllFiles(mask, (info) => Path.GetExtension(info.Name) == ".html").ToList();
IEnumerable<string> GetFilesFromDir(string dir) =>
Directory.EnumerateFiles(dir).Concat(
Directory.EnumerateDirectories(dir)
.SelectMany(subdir => GetFilesFromDir(subdir)));
У 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);
}
}
Деякі чудові відповіді, але ці відповіді не вирішили мого питання.
Як тільки виникає проблема з дозволом на папку: "Відмовлено у дозволі" код не працює. Це те, що я використовував для вирішення питання "Відмовлено у дозволі":
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); });
}
}
Сподіваюся, що це допомагає іншим.
Просте і чисте рішення
/// <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, тому що можу отримати файли 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();
Зауважте, що " . " Є дійсною схемою пошуку, якщо ви хочете подати файл за допомогою розширення.
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
? Немає потреби.
files
і ви більше не можете просто new List<FileInfo>()
ввести параметр, який був би марним. Можливо, слід здійснити певну оптимізацію та уникати створення нового об'єкта, якщо цього не потрібно.
ref
не робимо нічого зрозумілішого. ref
Мета «s, щоб змінити весь files
покажчик навіть для викликає метод: це небезпечна операція , і тут немає необхідності в тому , що ви можете просто заповнити список, вам не потрібно повторно точки в інший список на купи. ref
слід застосовувати лише в дуже конкретних випадках; більшість часу вам просто потрібно реалізувати речі більш функціонально-парадигмальним способом.
Щоб уникнути UnauthorizedAccessException
, я використовую:
var files = GetFiles(@"C:\", "*.*", SearchOption.AllDirectories);
foreach (var file in files)
{
Console.WriteLine($"{file}");
}
public static IEnumerable<string> GetFiles(string path, string searchPattern, SearchOption searchOption)
{
var foldersToProcess = new List<string>()
{
path
};
while (foldersToProcess.Count > 0)
{
string folder = foldersToProcess[0];
foldersToProcess.RemoveAt(0);
if (searchOption.HasFlag(SearchOption.AllDirectories))
{
//get subfolders
try
{
var subfolders = Directory.GetDirectories(folder);
foldersToProcess.AddRange(subfolders);
}
catch (Exception ex)
{
//log if you're interested
}
}
//get files
var files = new List<string>();
try
{
files = Directory.GetFiles(folder, searchPattern, SearchOption.TopDirectoryOnly).ToList();
}
catch (Exception ex)
{
//log if you're interested
}
foreach (var file in files)
{
yield return file;
}
}
}
Якщо вам потрібні лише імена файлів, і оскільки мені не дуже сподобалось більшість рішень тут (особливості чи читання), як щодо цього ледачого?
private void Foo()
{
var files = GetAllFiles("pathToADirectory");
foreach (string file in files)
{
// Use can use Path.GetFileName() or similar to extract just the filename if needed
// You can break early and it won't still browse your whole disk since it's a lazy one
}
}
/// <exception cref="T:System.IO.DirectoryNotFoundException">The specified path is invalid (for example, it is on an unmapped drive).</exception>
/// <exception cref="T:System.UnauthorizedAccessException">The caller does not have the required permission.</exception>
/// <exception cref="T:System.IO.IOException"><paramref name="path" /> is a file name.-or-A network error has occurred.</exception>
/// <exception cref="T:System.IO.PathTooLongException">The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters and file names must be less than 260 characters.</exception>
/// <exception cref="T:System.ArgumentNullException"><paramref name="path" /> is null.</exception>
/// <exception cref="T:System.ArgumentException"><paramref name="path" /> is a zero-length string, contains only white space, or contains one or more invalid characters as defined by <see cref="F:System.IO.Path.InvalidPathChars" />.</exception>
[NotNull]
public static IEnumerable<string> GetAllFiles([NotNull] string directory)
{
foreach (string file in Directory.GetFiles(directory))
{
yield return file; // includes the path
}
foreach (string subDir in Directory.GetDirectories(directory))
{
foreach (string subFile in GetAllFiles(subDir))
{
yield return subFile;
}
}
}
Найкоротший запис
string files = Directory.GetFiles(@"your_path", "*.jpg", SearchOption.AllDirectories);
Ось мій кут щодо цього, ґрунтуючись на Hernaldo's, якщо вам потрібно знайти файли з іменами певного шаблону, наприклад 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;
}
Перерахування файлів і папок для моделювання, спеціальна реалізація.
Це створює повний перелік усіх файлів і папок, починаючи з вашої стартової каталогу.
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);
Коротке і просте рішення
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);
Цей допоміг мені отримати всі файли в каталозі та підкаталогах, хтось може бути корисним. [Натхненний зверху відповідями]
static void Main(string[] args)
{
try
{
var root = @"G:\logs";
DirectorySearch(root);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
}
public static void DirectorySearch(string root, bool isRootItrated = false)
{
if (!isRootItrated)
{
var rootDirectoryFiles = Directory.GetFiles(root);
foreach (var file in rootDirectoryFiles)
{
Console.WriteLine(file);
}
}
var subDirectories = Directory.GetDirectories(root);
if (subDirectories?.Any() == true)
{
foreach (var directory in subDirectories)
{
var files = Directory.GetFiles(directory);
foreach (var file in files)
{
Console.WriteLine(file);
}
DirectorySearch(directory, true);
}
}
}
Деякі вдосконалені версії з максимальним lvl, щоб перейти в каталог і опцію для виключення папок:
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 виключається, оскільки він знаходиться у масиві виключених папок):
-folder1
file1.txt
-folder2
file2.txt
-folder5
-folder3
-folder4
file4.txt
file5.txt
Ось версія коду Б. Клей Шеннона не статична для файлів 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;
}
Дуже просте рішення, повертає список файлів.
public static List<string> AllFilesInFolder(string folder)
{
var result = new List<string>();
foreach (string f in Directory.GetFiles(folder))
{
result.Add(f);
}
foreach (string d in Directory.GetDirectories(folder))
{
result.AddRange(AllFilesInFolder(d));
}
return result;
}
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();
}