快速获取特定path中的所有文件和目录

我正在创build一个c#扫描目录的备份应用程序。 在我使用这样的东西之前,为了获取目录中的所有文件和子文件:

DirectoryInfo di = new DirectoryInfo("A:\\"); var directories= di.GetFiles("*", SearchOption.AllDirectories); foreach (FileInfo d in directories) { //Add files to a list so that later they can be compared to see if each file // needs to be copid or not } 

唯一的问题是,有时一个文件无法访问,我得到了几个错误。 我得到一个错误的例子是: 错误

因此,我创build了一个recursion方法,将扫描当前目录中的所有文件。 如果那个目录中有目录,那么该方法将被再次调用,通过该目录。 关于这个方法的好处是,我可以把文件放在一个try catch块中,让我可以select将这些文件添加到List,如果没有错误,并且如果我有错误,将目录添加到另一个列表。

 try { files = di.GetFiles(searchPattern, SearchOption.TopDirectoryOnly); } catch { //info of this folder was not able to get lstFilesErrors.Add(sDir(di)); return; } 

所以这个方法效果很好,唯一的问题是,当我扫描一个大的目录需要很多时间。 我怎么能加快这个过程? 我的实际方法是这样的情况下,你需要它。

 private void startScan(DirectoryInfo di) { //lstFilesErrors is a list of MyFile objects // I created that class because I wanted to store more specific information // about a file such as its comparePath name and other properties that I need // in order to compare it with another list // lstFiles is a list of MyFile objects that store all the files // that are contained in path that I want to scan FileInfo[] files = null; DirectoryInfo[] directories = null; string searchPattern = "*.*"; try { files = di.GetFiles(searchPattern, SearchOption.TopDirectoryOnly); } catch { //info of this folder was not able to get lstFilesErrors.Add(sDir(di)); return; } // if there are files in the directory then add those files to the list if (files != null) { foreach (FileInfo f in files) { lstFiles.Add(sFile(f)); } } try { directories = di.GetDirectories(searchPattern, SearchOption.TopDirectoryOnly); } catch { lstFilesErrors.Add(sDir(di)); return; } // if that directory has more directories then add them to the list then // execute this function if (directories != null) foreach (DirectoryInfo d in directories) { FileInfo[] subFiles = null; DirectoryInfo[] subDir = null; bool isThereAnError = false; try { subFiles = d.GetFiles(); subDir = d.GetDirectories(); } catch { isThereAnError = true; } if (isThereAnError) lstFilesErrors.Add(sDir(d)); else { lstFiles.Add(sDir(d)); startScan(d); } } } 

ant的问题,如果我试图处理exception,像这样的东西:

 DirectoryInfo di = new DirectoryInfo("A:\\"); FileInfo[] directories = null; try { directories = di.GetFiles("*", SearchOption.AllDirectories); } catch (UnauthorizedAccessException e) { Console.WriteLine("There was an error with UnauthorizedAccessException"); } catch { Console.WriteLine("There was antother error"); } 

如果发生exception,那么我得不到任何文件。

这种方法要快得多。 在电话簿中放置大量文件时只能打电话。 我的答:\外部硬盘驱动器包含几乎1太比特,因此它处理大量的文件时,会有很大的不同。

 static void Main(string[] args) { DirectoryInfo di = new DirectoryInfo("A:\\"); FullDirList(di, "*"); Console.WriteLine("Done"); Console.Read(); } static List<FileInfo> files = new List<FileInfo>(); // List that will hold the files and subfiles in path static List<DirectoryInfo> folders = new List<DirectoryInfo>(); // List that hold direcotries that cannot be accessed static void FullDirList(DirectoryInfo dir, string searchPattern) { // Console.WriteLine("Directory {0}", dir.FullName); // list the files try { foreach (FileInfo f in dir.GetFiles(searchPattern)) { //Console.WriteLine("File {0}", f.FullName); files.Add(f); } } catch { Console.WriteLine("Directory {0} \n could not be accessed!!!!", dir.FullName); return; // We alredy got an error trying to access dir so dont try to access it again } // process each directory // If I have been able to see the files in the directory I should also be able // to look at its directories so I dont think I should place this in a try catch block foreach (DirectoryInfo d in dir.GetDirectories()) { folders.Add(d); FullDirList(d, searchPattern); } } 

顺便说一句,我得到这个感谢您的评论吉姆Mischel

在.NET 4.0中有Directory.EnumerateFiles方法,它返回一个IEnumerable<string> ,并不加载所有的文件在内存中。 只有当您开始迭代返回的集合时,才会返回文件,并可以处理exception 。

.NET文件枚举方法的历史悠久。 问题是没有一个枚举大型目录结构的即时方法。 即使这个被接受的答案也有GC分配方面的问题。

我已经能够做的最好的事情是封装在我的库中,并作为CSharpTest.Net.IO命名空间中的FindFile ( source )类公开 。 该类可以枚举文件和文件夹,而不需要GC分配和string编组。

用法很简单,RaiseOnAccessDenied属性将跳过用户无权访问的目录和文件:

  private static long SizeOf(string directory) { var fcounter = new CSharpTest.Net.IO.FindFile(directory, "*", true, true, true); fcounter.RaiseOnAccessDenied = false; long size = 0, total = 0; fcounter.FileFound += (o, e) => { if (!e.IsDirectory) { Interlocked.Increment(ref total); size += e.Length; } }; Stopwatch sw = Stopwatch.StartNew(); fcounter.Find(); Console.WriteLine("Enumerated {0:n0} files totaling {1:n0} bytes in {2:n3} seconds.", total, size, sw.Elapsed.TotalSeconds); return size; } 

对于我的本地C:\驱动器,输出如下内容:

在232.876秒内枚举了总共307,707,792,662个字节的810,046个文件。

您的里程可能因驱动器速度而异,但这是我用托pipe代码枚举文件的最快方法。 事件参数是types为FindFile.FileFoundEventArgs的变异类,所以请确保您不要保留对它的引用,因为它的值会随着引发的每个事件而改变。

你可以使用它来获取所有的目录和子目录。 然后简单地循环处理文件。

 string[] folders = System.IO.Directory.GetDirectories(@"C:\My Sample Path\","*", System.IO.SearchOption.AllDirectories); foreach(string f in folders) { //call some function to get all files in folder } 

我知道这是旧的,但…另一种select可能是使用FileSystemWatcher像这样:

 void SomeMethod() { System.IO.FileSystemWatcher m_Watcher = new System.IO.FileSystemWatcher(); m_Watcher.Path = path; m_Watcher.Filter = "*.*"; m_Watcher.NotifyFilter = m_Watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; m_Watcher.Created += new FileSystemEventHandler(OnChanged); m_Watcher.EnableRaisingEvents = true; } private void OnChanged(object sender, FileSystemEventArgs e) { string path = e.FullPath; lock (listLock) { pathsToUpload.Add(path); } } 

这将允许您用一个非常轻量级的过程来观察文件更改的目录,然后可以使用它来存储已更改的文件的名称,以便在适当的时候备份它们。

(在另一个问题上从我的其他答案复制这篇文章)

search目录中的所有文件时显示进度

快速文件枚举

当然,正如你已经知道的那样,有很多方法来进行枚举本身…但是没有一个是瞬时的。 您可以尝试使用USN Journal of the file system进行扫描。 看看CodePlex中的这个项目: VB.NET中的MFT扫描器 …它在不到15秒的时间里find了我的IDE SATA(非SSD)驱动器中的所有文件,并find了311000个文件。

您将不得不通过path过滤文件,以便只返回您正在查找的path内的文件。 但这是工作的一部分!

也许这对你会有帮助。 您可以使用“ DirectoryInfo.EnumerateFiles ”方法,并根据需要处理UnauthorizedAccessException

 using System; using System.IO; class Program { static void Main(string[] args) { DirectoryInfo diTop = new DirectoryInfo(@"d:\"); try { foreach (var fi in diTop.EnumerateFiles()) { try { // Display each file over 10 MB; if (fi.Length > 10000000) { Console.WriteLine("{0}\t\t{1}", fi.FullName, fi.Length.ToString("N0")); } } catch (UnauthorizedAccessException UnAuthTop) { Console.WriteLine("{0}", UnAuthTop.Message); } } foreach (var di in diTop.EnumerateDirectories("*")) { try { foreach (var fi in di.EnumerateFiles("*", SearchOption.AllDirectories)) { try { // Display each file over 10 MB; if (fi.Length > 10000000) { Console.WriteLine("{0}\t\t{1}", fi.FullName, fi.Length.ToString("N0")); } } catch (UnauthorizedAccessException UnAuthFile) { Console.WriteLine("UnAuthFile: {0}", UnAuthFile.Message); } } } catch (UnauthorizedAccessException UnAuthSubDir) { Console.WriteLine("UnAuthSubDir: {0}", UnAuthSubDir.Message); } } } catch (DirectoryNotFoundException DirNotFound) { Console.WriteLine("{0}", DirNotFound.Message); } catch (UnauthorizedAccessException UnAuthDir) { Console.WriteLine("UnAuthDir: {0}", UnAuthDir.Message); } catch (PathTooLongException LongPath) { Console.WriteLine("{0}", LongPath.Message); } } }