惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Schneier on Security
The Register - Security
The Register - Security
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The GitHub Blog
The GitHub Blog
博客园 - 司徒正美
罗磊的独立博客
U
Unit 42
S
SegmentFault 最新的问题
Y
Y Combinator Blog
博客园_首页
Hugging Face - Blog
Hugging Face - Blog
J
Java Code Geeks
Schneier on Security
Schneier on Security
Know Your Adversary
Know Your Adversary
C
Check Point Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Simon Willison's Weblog
Simon Willison's Weblog
V
Vulnerabilities – Threatpost
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
阮一峰的网络日志
阮一峰的网络日志
The Hacker News
The Hacker News
博客园 - 叶小钗
C
Cybersecurity and Infrastructure Security Agency CISA
Spread Privacy
Spread Privacy
L
LINUX DO - 热门话题
T
The Exploit Database - CXSecurity.com
P
Palo Alto Networks Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Latest news
Latest news
L
Lohrmann on Cybersecurity
A
About on SuperTechFans
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
S
Securelist
A
Arctic Wolf
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Threatpost
Scott Helme
Scott Helme
博客园 - 聂微东
博客园 - 【当耐特】
T
Tenable Blog
I
Intezer
D
DataBreaches.Net
B
Blog RSS Feed
Security Latest
Security Latest
C
Cisco Blogs
T
Tor Project blog
N
Netflix TechBlog - Medium

博客园 - 东风125

.NET Actor Model Implementations Differ in Approach WCF 数据服务 4.5 XML 文档和数据 Why GUID primary keys are a database’s worst nightmare Conway's Game of Life: An Exercise in WPF, MVVM and C# A CIRCULAR PROGRESSBAR STYLE USING AN ATTACHED VIEWMODEL First MarkDown Blog 39. Volume Rendering Techniques Service Station - An Introduction To RESTful Services With WCF WPF Wonders: Transformations (and Robots!) Flipping elements with WPF FoLlow 的技术博客 利用索引降低并发事务引起的锁【转】 企业级应用架构模型-并发,事务,锁 Web service standards: SOAP, REST, OData, and more A Simple MVVM Example[Forward] The Truth About .NET Objects And Sharing Them Between AppDomains Three Sources of a Solid Object-Oriented Design 加快Bitmap的访问速度
Folder Recursion with C#
东风125 · 2015-08-31 · via 博客园 - 东风125

Some applications must read the folder structure beneath an existing folder or for an entire disk or attached device. The standard method in the Directory class can cause problems when used in this way. An alternative is to recursively read the folders.

Reading Folders

It is common to wish to read the entire folder structure of a disk when you are creating software that works with the file system. For example, you may wish to populate a TreeView control with the complete list of directories, or you might read the folders in order to compare them with another directory or with a backup copy.

The Directory class, which is a standard type within the .NET framework, includes a method, named GetDirectories, that allows you to read the folders within a given path, returning their names in a string array. You can use further methods of the Directory and File classes to work with the folders and their contents. An example of the GetDirectories method is shown below. This returns a list of folder names that can be found in the root of the C: drive.

NB: To run this code you need to reference the System.IO namespace so add the directive, "using System.IO;" to your code.

string[] folders = Directory.GetDirectories(@"c:\");

To instruct the method to work recursively, reading the folders, their subfolders and directories beneath these until the folder structure is exhausted, you can add the AllDirectoriessearch option, as shown below:

string[] folders = Directory.GetDirectories(@"c:\", "*", SearchOption.AllDirectories);

Unfortunately, this has problems. Key amongst these is that some of the folders that you attempt to read could be configured so that the current user may not access them. Rather than ignoring folders to which you have restricted access, the method throws anUnauthorizedAccessException. However, we can circumvent this problem by creating our own recursive folder search code.

Folder Recursion

Let's start with some simple folder recursion code that recreates the flawed functionality of the GetDirectories method. We'll create it within a console application and show its activity by outputting folder name as they are examined. In a real application you could build and return a list or array, or use an iterator to return the values as they are required, thus avoiding the delay caused by reading large folder structures ahead of the time they are needed.

The code below shows the basic recursive method. The Main method callsShowAllFoldersUnder, passing in the starting path. In this case we are going to display all folders starting from the root of the C: drive.

ShowAllFoldersUnder does the real work. When this method is called it uses the basic version of GetDirectories to obtain the folder list for directories immediately within the provided path. It then loops through these folders, first displaying the name, then calling itself, passing the folder name, to look one level deeper. This recursive nature causes all folders to be examined, unless an exception is thrown.

static void Main(string[] args)
{
    Console.WriteLine(@"c:\");
    ShowAllFoldersUnder(@"c:\", 0);
}

private static void ShowAllFoldersUnder(string path, int indent)
{
    foreach (string folder in Directory.GetDirectories(path))
    {
        Console.WriteLine("{0}{1}", new string(' ', indent), Path.GetFileName(folder));
        ShowAllFoldersUnder(folder, indent + 2);
    }
}

To avoid UnauthorizedAccessExceptions stopping the execution, we need to add a try / catch block around the foreach loop. We can use this to catch only that type of exception and ignore it. This means that the folders to which the user does not have access will not be displayed. The updated ShowAllFolders code is as follows.

private static void ShowAllFoldersUnder(string path, int indent)
{
    try
    {
        foreach (string folder in Directory.GetDirectories(path))
        {
            Console.WriteLine("{0}{1}", new string(' ', indent), Path.GetFileName(folder));
            ShowAllFoldersUnder(folder, indent + 2);
        }
    }
    catch (UnauthorizedAccessException) { }
}

Reparse Points

Something else that we must deal with is reparse points, or junction points. Most disks used by Windows operating systems are formatted using the New Technology File System, or NTFS. This allows disks to be mounted in interesting ways. In addition to the usual assignment of drive letters, such as C:, disks can be mounted within folders. This means that when you use Windows Explorer to browse to the C:\OtherDisk folder, you may be seeing the contents of another disk or partition altogether.

Junction points generate a problem when recursively scanning folders; drives can be mounted in such a way as to create infinite directory structures. For example, the disk containing your C: drive could be mounted within a folder named, "C:\Infinite". If you looked inside this folder you would find everything that is in the root of C:, including the "Infinite" folder. You could continue to drill down into that folder, each time seeing the same subfolders and files.

To avoid infinite loops, we need to check that a folder is not a junction point. We can do this by reading each folder's attributes and checking if it is a reparse point. To get the attributes we use the File.GetAttributes method, which returns an enumeration that represents a bit field. We can then use the bitwise AND operator to check for the existence of the ReparsePointflag.

Using this information we can create the final version of ShowAllFoldersUnder, as follows:

private static void ShowAllFoldersUnder(string path, int indent)
{
    try
    {
        if ((File.GetAttributes(path) & FileAttributes.ReparsePoint)
            != FileAttributes.ReparsePoint)
        {
            foreach (string folder in Directory.GetDirectories(path))
            {
                Console.WriteLine(
                    "{0}{1}", new string(' ', indent), Path.GetFileName(folder));
                ShowAllFoldersUnder(folder, indent + 2);
            }
        }
    }
    catch (UnauthorizedAccessException) { }
}