【问题标题】:How can I recursively count files and folders in Windows with C#?如何使用 C# 递归计算 Windows 中的文件和文件夹?
【发布时间】:2012-07-19 03:01:29
【问题描述】:

2012 年 8 月 8 日编辑: 我对正在使用的代码进行了一些重大更改,最后希望得到一些新的帮助我遇到的问题。我将重写这个问题的大部分内容。

我有一个小程序,它递归地遍历目标目录下的每个文件和文件夹,检查特定字符的名称。它工作得很好,但我正在寻求有关如何使特定方法更快工作的帮助。

这是我目前正在使用的代码。这只是启动所有方法的几行代码:

if(getFullList(initialPathTB.Text))
            SearchFolder();  

而这两种方法是你需要看的:

private void SearchFolder()
{
    int      newRow;
    int      numItems = 0;

    numItems = itemsMaster.Length;

    for (int x = 0; x < numItems; x++)
    {
        if (hasIllegalChars(itemsMaster[x]) == true)
        {
            newRow = dataGridView1.Rows.Add();
            dataGridView1.Rows[newRow].Cells[0].Value = itemsMaster[x];
            filesFound++;
        }
    }
}

private bool getFullList(string folderPath)
{
    try
    {
        if (checkBox17.Checked)
            itemsMaster = Directory.GetFileSystemEntries(folderPath, "*", SearchOption.AllDirectories);
        else
            itemsMaster = Directory.GetFileSystemEntries(folderPath, "*", SearchOption.TopDirectoryOnly);
        return true;
    }
    catch (UnauthorizedAccessException e)
    {
        if(folderPath[folderPath.Length - 1] != '\\')
            folderPath += @"\";
        if (e.Message == "Access to the path '" + folderPath + "' is denied.")
        {
            MessageBox.Show("You do not have read permission for the following directory:\n\n\t" + folderPath + "\n\nPlease select another folder or log in as a user with read access to this folder.", "Access Denied", MessageBoxButtons.OK, MessageBoxIcon.Error);
            folderPath = folderPath.Substring(0, folderPath.Length - 1);
        }
        else
        {
            if (accessDenied == null)
                accessDenied = new StringBuilder("");
            accessDenied.AppendLine(e.Message.Substring(20, e.Message.Length - 32));
        }
        return false;
    }
}

initialPathTB.Text 填充了类似“F:\COMMON\Administration”的内容。

这是我的问题。当传递给folderPath 的顶层是用户没有读取权限的顶层时,一切正常。当顶级 和所有从属目录 是用户具有读取权限的文件夹时,一切都会再次正常工作。问题在于用户对顶层具有读取权限但对更深层次的某些子文件夹没有读取权限的目录。这就是为什么getFullList() 是一个布尔值;如果有任何 UnauthorizedAccessExceptions 则 itemsMaster 保持为空,SearchFolder()numItems = itemsMaster.Length; 上失败。

我想要的是用folderPath 中的每个项目填充itemsMaster,并简单地跳过用户没有读取权限的项目,但我不知道如何在没有递归爬行和检查每个目录。

此代码的运行速度比我的旧方法快得多,所以我不想完全放弃它。有什么办法可以让Directory.GetFileSystemEntries() 方法做我想做的事吗?

【问题讨论】:

  • 与在 Windows 资源管理器中执行文件夹属性相比,您的程序需要多长时间才能计数?只是一个猜测,但我希望您无法比 Windows 本身更快地做到这一点,这在这么大的东西上可能会很慢。
  • items[x] 上的 ToString() 是否必要?只是一个不需要的函数调用,会导致延迟,尤其是在循环中。
  • @JoeEnos - 我的方法肯定比通过 Windows 资源管理器检查文件夹属性花费的时间要长得多。
  • 只是出于兴趣,你的程序是做什么的,"检查特定字符的名称"是什么意思?如果您正在检查文件名,执行整个程序的成本可能几乎与计算文件的成本一样高。
  • @TimSchmelter - 实际上这是一个好点。总体而言,使用我上面的方法计算每个子文件夹的内容并将所有这些项目的路径保存到数组中,然后检查数组中是否存在非法字符,而不是再次访问文件系统,这可能会更快...

标签: c# recursion filesystems directory


【解决方案1】:
Directory.GetFileSystemEntries(folderPath, "*", SearchOption.AllDirectories).Length

或其他选项(使用此选项,请记住 fullstring 中的前 3-5 个元素将是您应该删除的输出中的垃圾文本):

Process process = new Process();
List<string> fullstring = new List<string>();

process.StartInfo.FileName = "cmd.exe";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.UseShellExecute = false;
process.OutputDataReceived += (sender, args2) => fullstring.Add(args2.Data);

process.Start();

process.StandardInput.WriteLine(@"dir /b /s c:\temp | find """" /v");
process.BeginOutputReadLine();

process.WaitForExit(10000); //or whatever is appropriate time

process.Close();

如果您想更好地跟踪错误,请进行以下更改:

全局声明List&lt;string&gt; fullstring = new List&lt;string&gt;();,然后更改OutputDataReceived的事件处理程序如下:

    process.OutputDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
}

static void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    try
    {
        fullstring.Add(e.Data);
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.ToString());
        //log exception
    }
}

【讨论】:

  • 但这在现代硬盘上会有很大的滞后
  • @ColeJohnson - 它确实需要一段时间,但不像我的方法那样长。
  • 除非你想在非托管代码中这样做,否则我认为你不能比上面的框架方法快得多。
  • 如果我使用Directory.GetFileSystemEntries(folderPath, "*", SearchOption.AllDirectories) 填充数组,但folderPath 下有一个或多个子目录,用户没有读取权限,catch 子句将如何处理@987654329 @?它会只列出第一个并退出填充列表,还是会继续到下一个文件/目录?如果它继续下去,我有什么方法可以捕获引发异常的目录列表?
  • @jonnyp 如果您有后续问题可以在 cmets 中发帖,我会尽力解答。
【解决方案2】:

您写道:“我希望进度条实际指示程序在项目列表中的距离,因此我需要一些项目来设置 ProgressBar.Maximum 属性。”

这是一种特定的愿望,我不确定在特定情况下它是否值得。如果你的 ProgressBar 是(比如说)800 px 宽,1 个百分点就是 0.125px 宽。对于“超过 10 万个项目”的列表——让我们将其设为至少 100,000 个——您必须处理 8,000 个项目才能移动条形以移动单个像素。您的程序处理 8,000 个项目需要多长时间?这将帮助您了解您正在向用户提供什么样的实际反馈。如果花费的时间过长,即使它正在工作,它也可能看起来像是挂了。

如果您希望提供良好的用户反馈,我建议您将 ProgressBar 的样式设置为 Marquee 并提供“正在检查文件 #x”文本指示器。

【讨论】:

  • 这是一个公平的观点。我对 C# 还是很陌生(我相信每个人都可以从我上面的代码块中看出)并且也一直在使用这个应用程序作为学习体验。
  • 我对我的代码做了一些相当大的改动,你介意再帮我看看我的问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-23
  • 1970-01-01
  • 2018-10-10
相关资源
最近更新 更多