c#如何遍历文件系统并分配编号



我遇到了一个问题,正在处理

我想遍历本地PC文件夹,包括目录,并根据文件系统层次结构中的每个文件夹计算一个编号系统。

根文件夹应计算为1,2,3等

如果文件夹一中有三个子文件夹,则计算的数字应为:1.1、1.2、1.3

如果上面的子文件夹中有三个子文件夹,则计算的数字应为:1.1.1、1.1.2、1.1.3

如果文件夹二(根文件夹)中有三个子文件夹,则计算的数字应为:2.1、2.2、2.3

或者用另一种方式表达:

 1   Root Folder 
 1.1   Root Sub Folder 1
 1.1.1   Sub Folder
 1.1.2     Sub Folder
 1.2 Root Sub Folder 2
 1.2.1 List item
 1.2.2   List item 

等等。等

然后应该将此逻辑应用于所有文件夹和子文件夹。

输出示例

1.1.1 | "c:RootFolder1Folder1"

到目前为止,我所做的在某些情况下似乎可以正常工作,但在其他情况下可能会失败:

    private string rootpath = @"C:FolderHierarchy";
    private string FolderSequenceCountBase = "";
    private int CurrentRootPathCount = 0;
    private int Counter = 0;
    private void CalculateFolderHierarchyNumbers()
    {
        //Get First List of Folders
        string[] Dirs = Directory.GetDirectories(rootpath, "*.*", SearchOption.TopDirectoryOnly);
        for (int i = 0; i < Dirs.Count(); i++)
        {
            FolderSequenceCountBase = (i + 1).ToString();
            CurrentRootPathCount = i + 1;
            Console.WriteLine("Processed folder '{0}'.", Dirs[i] + " = " + (i + 1));                
            GetSubDirs(Dirs[i]);
        }
    }
    private void GetSubDirs(string item)
    {
        //Get next list of folders in the folder hierarchy
        string[] SubDirs = Directory.GetDirectories(item, "*.*", SearchOption.TopDirectoryOnly);
        foreach (var DirPath in SubDirs)
        {
            //Increment count of folders within the current folder list
            Counter += 1;
            Console.WriteLine("Processed folder '{0}'.", DirPath + " = " + FolderSequenceCountBase + "." + Counter);
        }
        Counter = 0;
        //Get next list of folders in the folder hierarchy
        foreach (var DirPath in SubDirs)
        {
            FolderSequenceCountBase += ".1";
            GetSubDirs(DirPath);  
        }
    }

希望这是清楚的。

谢谢Rick

所以你想找到一个文件,并得到它在of目录和所有父目录中的编号?自从我发现它很有趣,我就从头开始写了一些东西。请注意,它目前还没有经过测试,但它可能会给你一个想法:

public static IEnumerable<FileEntryInfo> EnumerateFindFiles(string fileToFind, StringComparison comparison = StringComparison.CurrentCultureIgnoreCase, DirectoryInfo rootDir = null, string[] drivesToSearch = null)
{
    IEnumerable<FileEntryInfo> foundEntries = Enumerable.Empty<FileEntryInfo>();
    if (rootDir != null && drivesToSearch != null)
        throw new ArgumentException("Specify either the root-dir or the drives to search, not both");
    else if (rootDir != null)
    {
        foundEntries = EnumerateFindEntryRoot(fileToFind, rootDir, comparison);
    }
    else
    {
        if (drivesToSearch == null) // search the entire computer
            drivesToSearch = System.Environment.GetLogicalDrives();
        foreach (string dr in drivesToSearch)
        {
            System.IO.DriveInfo di = new System.IO.DriveInfo(dr);
            if (!di.IsReady)
            {
                Console.WriteLine("The drive {0} could not be read", di.Name);
                continue;
            }
            rootDir = di.RootDirectory;
            foundEntries = foundEntries.Concat(EnumerateFindEntryRoot(fileToFind, rootDir, comparison));
        }
    }
    foreach (FileEntryInfo entry in foundEntries)
        yield return entry;
}
public class FileEntryInfo
{
    public FileEntryInfo(string path, int number)
    {
        this.Path = path;
        this.Number = number;
    }
    public int Number { get; set; }
    public string Path { get; set; }
    public FileEntryInfo Root { get; set; }
    public IEnumerable<int> GetNumberTree()
    {
        Stack<FileEntryInfo> filo = new Stack<FileEntryInfo>();
        FileEntryInfo entry = this;
        while (entry.Root != null)
        {
            filo.Push(entry.Root);
            entry = entry.Root;
        }
        while(filo.Count > 0)
            yield return filo.Pop().Number;
        yield return this.Number; 
    }

    public override bool Equals(object obj)
    {
        FileEntryInfo fei = obj as FileEntryInfo;
        if(obj == null) return false;
        return Number == fei.Number && Path == fei.Path;
    }
    public override int GetHashCode()
    {
        return Path.GetHashCode();
    }
    public override string ToString()
    {
        return Path;
    }
}
private static IEnumerable<FileEntryInfo> EnumerateFindEntryRoot(string fileNameToFind, DirectoryInfo rootDir, StringComparison comparison = StringComparison.CurrentCultureIgnoreCase)
{
    Queue<FileEntryInfo> queue = new Queue<FileEntryInfo>();
    FileEntryInfo root = new FileEntryInfo(rootDir.FullName, 1);
    queue.Enqueue(root);
    while (queue.Count > 0)
    {
        FileEntryInfo fe = queue.Dequeue();
        List<FileEntryInfo> validFiles = new List<FileEntryInfo>();
        try
        { // you cannot yield from try-catch, hence this approach
            FileAttributes attr = File.GetAttributes(fe.Path);
            //detect whether its a directory or file
            bool isDirectory = (attr & FileAttributes.Directory) == FileAttributes.Directory;
            if (isDirectory)
            {
                int entryCount = 0;
                foreach (string entry in Directory.EnumerateFileSystemEntries(fe.Path))
                {
                    entryCount++;
                    FileEntryInfo subEntry = new FileEntryInfo(entry, entryCount);
                    subEntry.Root = fe;
                    queue.Enqueue(subEntry);
                    attr = File.GetAttributes(entry);
                    isDirectory = (attr & FileAttributes.Directory) == FileAttributes.Directory;
                    if(!isDirectory)
                        validFiles.Add(subEntry);
                }
            }
        } catch (Exception ex)
        {
            Console.Error.WriteLine(ex); // ignore, proceed
        }
        foreach (FileEntryInfo entry in validFiles)
        {
            string fileName = Path.GetFileName(entry.Path);
            if (fileName.Equals(fileNameToFind, comparison))
                yield return entry;
        }
    }
}

以下是我的测试方法:

var allEntriesFound = EnumerateFindFiles("PresentationFramework.dll").ToList();
if(allEntriesFound.Any())
{
    foreach (FileEntryInfo entry in allEntriesFound)
        Console.WriteLine("{0}: Number: {1}", entry.Path, entry.Number);
    // here your exact requirement:
    string result = string.Join(".", allEntriesFound[0].GetNumberTree());
    Console.WriteLine(result);
}

还添加了一种指定根目录的方法,以防止搜索整个文件系统,用法:

var allEntriesFound = EnumerateFindFiles(
  "PresentationFramework.dll", 
  StringComparison.CurrentCultureIgnoreCase,
  new DirectoryInfo(@"C:Windows"))
.ToList();

最新更新