使用 DirectoryInfo.EnumerateFiles 和 "subst" 命令抛出未处理的 DirectoryNotFound 异常

Unhandled DirectoryNotFound exception thrown using DirectoryInfo.EnumerateFiles and "subst" command

背景:

我正在尝试编写一个小程序,递归地遍历用户指定文件夹(及其所有子文件夹)中包含的所有文件。该程序应该检查每个文件的大小,如果它与用户定义的值匹配,则将它们的完整路径 (File.FullName) 复制到我在该程序的唯一形式上设置的文本框控件。 问题在于,由于该程序的预期用途(处理从外部驱动器上损坏的分区中恢复的文件和文件夹),路径长度通常会远远超过最大路径长度限制。为了略微规避这一点,我决定使用 Win32 命令行函数 "subst".

将用户选择的起始目录映射到虚拟驱动器

相关代码:

private void button1_Click(object sender, EventArgs e)
    {
        if (txtboxSizeFilter.Text != "")//code will execute only if a size filter has been provided by the user
        {

            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
                {
                    List<char> driveLetters = new List<char>(26); // Allocate space for alphabet
                    for (int i = 65; i < 91; i++) // increment from ASCII values for A-Z
                    {
                        driveLetters.Add(Convert.ToChar(i)); // Add uppercase letters to possible drive letters
                    }

                    foreach (string drive in Directory.GetLogicalDrives())
                    {
                        driveLetters.Remove(drive[0]); // removed used drive letters from possible drive letters
                    }

                    GlobalVars.Drive = driveLetters[0].ToString() + ":"; //gets the next available drive letter to be used as the virtual drive and adds a convenient ":" at the end

                    string command = "subst " + GlobalVars.Drive + " " + "\"" + folderBrowserDialog1.SelectedPath.ToString() + "\""; //command to be passed to "cmd". Ex. Content= subst J: "C:\users\someuser\somelongnamefolder\some longer name folder with spaces" 
                    System.Diagnostics.Process.Start("cmd.exe", @"/c " + command);//launches the command prompt and initiates subst. This section has been tested and works fine.

                    DirectoryInfo DI = new DirectoryInfo(GlobalVars.Drive);//here i start at the drive letter that points to the desired directory.
                   foreach (var fi in DI.EnumerateFiles("*", SearchOption.AllDirectories))//searches for any file in all dirs. THE EXCEPTION "DirectoryNotFound" OBJECT OF THIS QUESTION IS THROWN EXACTLY HERE.
                   {
                        try //I need this because I might throw a PathTooLongException despite my use of subst
                        {
                            if (fi.Length == Convert.ToInt64(txtboxSizeFilter.Text))//if the size of the file is = to target size then I add the full path name to the textbox along with its actual size (for debug purposes only).
                            {
                                txtboxResults2Confirm.Text = txtboxResults2Confirm.Text + fi.FullName.ToString() + "_" + fi.Length.ToString() + Environment.NewLine;
                            }
                         }
                         catch (PathTooLongException)//if the path is too long, indicate it with the codeword "SKIP"
                         {
                            txtboxResults2Confirm.Text = txtboxResults2Confirm.Text + "SKIP" + Environment.NewLine;
                         }

                    }   
                    btnConfirm.Enabled = true;//enables the other button on the form that will actually delete the files.
                }
        }
        else
        {
            MessageBox.Show("INPUT SIZE FIRST!");
        }
    }

Problem/Research/Question:

如评论和磁贴中所述,未处理的 DirectoryNotFound 异常发生在第二个 foreach 语句中(如 IDE、Microsoft Visual Studio Ultimate 2013 所示)。一步一步调试表明foreach循环实际上工作了一段时间然后"randomly"抛出异常。我能够验证它是否遍历了根目录中的所有文件,并且至少遍历了第一个子目录的大部分而没有任何问题(因为大量 files/subdirectories 我无法查明故障发生的确切位置)。错误指出找不到的目录是根目录(因此,按照注释中的示例:"Unable to find J:\")。我试图跟随第一个 catch 和另一个 catch 来处理 DirectoryNotFound 异常,但没有用,这是有道理的,因为异常似乎直接起源于 foreach 语句。我还尝试将整个 foreach 语句包装到一个 try-catch 框架中,但没有任何运气。最后,摆脱整个 "subst" 部分并仅使用用户选择的路径不会产生此类错误。 我的问题是,为什么抛出异常?为什么我无法以任何方式处理它?是否有解决此问题的替代方法来确保避免 DirectoryNotFound 异常?

Process.Start 正是这样做的:它启动了一个新进程(具有自己的主线程等),该进程可能会在原始程序中的下一行代码执行时完成,也可能不会完成。有几种方法可以解决这个问题:a) 调用 DefineDosDevice,这意味着 "subst" 命令在当前程序线程中运行,或者 b) 获取到 cmd 进程的管道并监听它是否完成。都是中等难度,选你的毒

当然,您遇到的异常是因为 subst 命令在执行枚举(尚未取消别名)目录的代码时没有及时完成。