【问题标题】:Scanning a drive with drilldowns using C#?使用 C# 扫描带有向下钻取的驱动器?
【发布时间】:2010-10-30 11:20:56
【问题描述】:

我正在尝试创建一个扫描驱动器的应用程序。不过,棘手的部分是我的驱动器包含一组文件夹,这些文件夹在文件夹中包含文件夹并包含文档。我正在尝试扫描驱动器,拍摄所有文档和文件夹的“快照”,然后转储到 .txt 文件中。
我第一次运行这个应用程序时,输出将是一个包含所有文件夹和文件的文本文件。
我第二次运行此应用程序时,它将获取 2 个文本文件(我第二次运行该应用程序时生成的文件和我第一次运行该应用程序时生成的 .txt 文件)并比较它们...报告什么已被移动/覆盖/删除。

有人有这方面的代码吗?我是这个 C# 东西的新手,任何帮助将不胜感激。

提前致谢。

【问题讨论】:

    标签: c# file comparison


    【解决方案1】:

    我们在 80 年代学到的一件事是,如果真的很想使用递归进行文件系统遍历,但是当您这样做时,有人会创建一个具有嵌套级别的文件系统,这会导致您的堆栈溢出。使用基于堆的文件系统遍历要好得多。

    这是我拼凑的一门课,就是这样做的。它不是超级漂亮,但做得很好:

    using System;
    using System.IO;
    using System.Collections.Generic;
    
    namespace DirectoryWalker
    {
        public class DirectoryWalker : IEnumerable<string>
        {
            private string _seedPath;
            Func<string, bool> _directoryFilter, _fileFilter;
    
            public DirectoryWalker(string seedPath) : this(seedPath, null, null)
            {
            }
    
            public DirectoryWalker(string seedPath, Func<string, bool> directoryFilter, Func<string, bool> fileFilter)
            {
                if (seedPath == null)
                    throw new ArgumentNullException(seedPath);
                _seedPath = seedPath;
                _directoryFilter = directoryFilter;
                _fileFilter = fileFilter;
            }
    
            public IEnumerator<string> GetEnumerator()
            {
                Queue<string> directories = new Queue<string>();
                directories.Enqueue(_seedPath);
                Queue<string> files = new Queue<string>();
                while (files.Count > 0 || directories.Count > 0)
                {
                    if (files.Count > 0)
                    {
                        yield return files.Dequeue();
                    }
    
                    if (directories.Count > 0)
                    {
                        string dir = directories.Dequeue();
                        string[] newDirectories = Directory.GetDirectories(dir);
                        string[] newFiles = Directory.GetFiles(dir);
                        foreach (string path in newDirectories)
                        {
                            if (_directoryFilter == null || _directoryFilter(path))
                                directories.Enqueue(path);
                        }
                        foreach (string path in newFiles)
                        {
                            if (_fileFilter == null || _fileFilter(path))
                                files.Enqueue(path);
                        }
                    }
                }
            }
    
            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
        }
    }
    

    典型用法是这样的:

    DirectoryWalker walker = new DirectoryWalker(@"C:\pathToSource\src", null, (x => x.EndsWith(".cs")));
    foreach (string s in walker)
    {
        Console.WriteLine(s);
    }
    

    递归列出所有以“.cs”结尾的文件

    【讨论】:

    • 很好的答案比我的好多了,所以我要删除我的。
    • 这就是我来这里的原因;像这样的好答案。回答这个问题的人在这里有一篇关于这个概念的精彩后续文章:atalasoft.com/cs/blogs/stevehawley/archive/2009/06/02/…
    • 不错的代码。但是,仍然存在内存不足的问题。在几乎所有现代文件系统中,遍历时都可能存在循环(由于符号链接)!是的,Windows 也有这个。您需要对此进行检测,否则使用这种方法也会导致内存不足。更好地使用 Directory.GetFiles(..., SearchOption.AllDirectories)
    • @plinth 我遇到了管理错误。您有解决授权问题的解决方案吗?
    【解决方案2】:

    比您的文本文件比较更好的方法是使用FileSystemWatcher Class

    侦听文件系统更改通知并在目录或目录中的文件更改时引发事件。

    您可以记录更改,然后根据需要从该日志生成报告。

    【讨论】:

    • 是的,FileSystemWatcher 没问题,除非您一次将大量文件转储到您身上,那么您需要知道如何处理它。发生这种情况时,我在获取所有事件时遇到了问题(我的系统中一次转储了数千个文件)。
    • P.S.我所做的是等待任何文件事件,关闭事件挂钩,处理文件,完成后轮询几秒钟以查看是否有更多文件出现,重新启用 FileSystemWatcher。
    【解决方案3】:

    您可以轻松地为此使用 DirectoryInfo/FileInfo 类。

    基本上实例化 DirectoryInfo 类的一个实例,指向 c:\ 文件夹。然后使用它的对象遍历文件夹结构。

    http://msdn.microsoft.com/en-us/library/system.io.directoryinfo.aspx 的代码很容易翻译。

    现在,您问题的另一部分是精神错乱。您可以相对容易地找到两个文件之间的差异,但是将其转换为已移动/删除/等的内容将采用一些相当高级的逻辑结构。毕竟,如果我有两个文件,均名为 myfile.dat,一个位于 c:\foo,另一个位于 c:\notfoo,如果我删除位于c:\foo?另一个例子是,如果我有一个文件 myfile2.dat 并将其从 c:\bar 复制到 c:\notbar 是否被视为移动?如果我在星期二复制它,然后在星期四删除 c:\bar\myfile2.dat,会发生什么情况——这是移动还是删除?如果我在每个星期一而不是每天运行程序,答案会改变吗?

    有一大堆问题,以及它们相应的逻辑结构,您需要考虑 amd 代码才能构建该功能,即使那样,它也不是 100% 正确的,因为它不是分页文件系统随着更改的发生——总是存在由于时间、逻辑结构、处理时间、应用程序运行时间或仅仅由于计算机的纯粹反常而在您的逻辑中没有正确报告的场景的可能性。

    此外,处理时间会随着驱动器的大小呈指数增长。毕竟,您需要对照每个其他文件检查每个文件以确定它的状态,而不是它之前的状态。我不想在家里对我的 600+GB 驱动器运行这个,更不用说我在工作服务器上的 40TB 驱动器了。

    【讨论】:

    • 我会说文件比较将完成文件夹到文件夹。如上一次运行应用程序时生成的 .txt 转储文件中的 C:\foo 将与我上次运行应用程序时生成的 C:\foo 进行比较。如果我打算这样做,它仍然是精神错乱吗?
    • 这有点不同,也没有那么疯狂,因为您所做的只是比较 X 文件是否仍在 Y 目录中。也就是说,Dennis Palmer 有一个更好的主意,在 FileSystemWatcher 类(我不知道)中,并利用服务/任务托盘应用程序动态记录文件更改
    猜你喜欢
    • 1970-01-01
    • 2018-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-04
    • 1970-01-01
    相关资源
    最近更新 更多