DirectoryInfo returns 从不同方法调用时的不同值

DirectoryInfo returns different values when called from different methods

我一直在研究一种目录信息查看器。 第一个阶段是创建和填充 TreeView 模型,在编码过程中,我嵌套了一个方法来收集有关该目录中文件的信息。 一切正常,返回的值我们是正确的等等。

现在在代码清理阶段,当我尝试从 TreeView 创建中获取该方法时,我得到的值甚至不接近原始值(例如 90 MB 而不是 1.2 TB)。

下面标记了问题的代码:

private static int itemCount = 0;
private static long folderSizeInfo = 0;

public static void ListDirectory(string path)
    {
        (...)

        var rootDirectoryInfo = new DirectoryInfo(path);
        MainWindow.newWindowReport.Drzewko.Items.Add(CreateDirectoryNode(rootDirectoryInfo));

        //this does not work if invoked from here <----------------- FIX ME!
        //DirectoryMainOperation(rootDirectoryInfo);

        //need to run this once more to get data from root
        DirectoryContent_Operation(rootDirectoryInfo);

        (...)
    }

    private static TreeViewItem CreateDirectoryNode(DirectoryInfo directoryInfo)
    {
        var directoryNode = new TreeViewItem { Header = directoryInfo.Name };

        try
        {
            foreach (var directory in directoryInfo.GetDirectories())
            {
                if (!IsIgnorable(directory.Name))
                {
                    directoryNode.Items.Add(CreateDirectoryNode(directory));

                    //this method somehow only works here <------------------------ FIX ME!
                    DirectoryContent_Operation(directory);
                }
            }
        }
        catch (UnauthorizedAccessException)
        {
            //Console.WriteLine("Path is not accessible: {0}", i);
        }

        return directoryNode;
    }

    //-------------------TO BE FIXED------------------
    private static void DirectoryMainOperation(DirectoryInfo directoryInfo)
    {
        try
        {
            foreach (var directory in directoryInfo.GetDirectories())
            {
                if (!IsIgnorable(directory.Name))
                {
                    DirectoryContent_Operation(directory);
                }
            }
        }
        catch (UnauthorizedAccessException)
        {
            //Console.WriteLine("Path is not accessible: {0}", i);
        }
    }

    private static void DirectoryContent_Operation(DirectoryInfo targetDir)
    {
        try
        {
            foreach (var file in targetDir.EnumerateFiles("*", SearchOption.TopDirectoryOnly))
            {
                itemCount++;
                folderSizeInfo += file.Length;

                fileTable.Add(new FileExtension_List
                {
                    FileFormat = file.Extension,
                    Category = extDB.Translation(file.Extension.ToUpper()),
                    Count = 1,
                    TotalSize = file.Length
                });
            }
        }
        catch (UnauthorizedAccessException)
        {
        }
        catch (Exception ex)
        {
        }
    }

要点是,如果我从以下位置调用“DirectoryContent_Operation(目录)”:

  1. "CreateDirectoryNode(DirectoryInfo directoryInfo)" 它 returns 1.2 TB(正确值)
  2. “DirectoryMainOperation(DirectoryInfo directoryInfo)”它 returns 90 MB。

从看起来像 DirectoryMainOperation returns 由于 UnauthorizedAccessException 过早,因此不返回所有目录。在 DirectoryContent_Operation 中,您通过捕获 Exception!

吞下 每个 异常

请删除 try-catch(所有地方)以查看(内部)异常消息的确切含义以及抛出异常的位置..

请注意,吞噬异常总是一种代码味道,并且可能会引入错误,这真的很难识别。
如果您无法处理异常(将应用程序恢复到稳定状态),则应用程序必须崩溃。然后修复崩溃的原因。
在考虑是否以及如何处理异常之前,请先考虑如何避免它。
同样从性能的角度来看,强烈建议避免昂贵的异常。

您的问题表明让异常使应用程序崩溃以了解实现错误以及防止不希望的静默副作用(例如不完整的目录列表)是多么重要。吞噬异常使您的应用程序处于不可预测的状态,这将导致很多错误行为,这些错误行为最初可能不会被用户注意到。对于使用您的应用程序来管理其业务的客户来说,这可能会付出高昂的代价。

为了避免 UnauthorizedAccessException 在您的情况下,您可以使用 DirectoryInfo.EnumerateDirectories(String, EnumerationOptions),它仅适用于 .NET Core(自版本 2.1 起)。
它通过默认跳过禁止的目录来避免抛出 UnauthorizedAccessException 异常。

或者,仅枚举顶级目录。然后检查每个子目录是否被禁止,然后再继续递归枚举子目录的顶级目录。下面的递归枚举很可能会解决你的问题

public void ListDirectory(string path)
{
  var rootDirectoryInfo = new DirectoryInfo(path);    
  var rootDirectoryNode = new TreeViewItem { Header = directoryInfo.Name };     
  MainWindow.newWindowReport.Drzewko.Items.Add(rootDirectoryNode);
  CreateDirectoryNode(rootDirectoryInfo, rootDirectoryNode);
}

private static void CreateDirectoryNode(DirectoryInfo parentDirectory, TreeViewItem parentDirectoryNode)
{
  foreach (DirectoryInfo childDirectory in parentDirectory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly))
  {
    var childDirectoryNode = new TreeViewItem { Header = childDirectory.Name };

    parentDirectoryNode.Items.Add(childDirectoryNode);

    // Don't enter forbidden directories
    // and optionally hidden directories too
    if (childDirectory.Attributes.HasFlag(FileAttributes.System) 
      || childDirectory.Attributes.HasFlag(FileAttributes.Hidden))
    {  
      continue;
    }

    // Recursively iterate over child's subdirectories
    CreateDirectoryNode(childDirectory, childDirectoryNode);
    DirectoryContent_Operation(childDirectory);
  }
}

private static void DirectoryMainOperation(DirectoryInfo parentDirectory)
{
  foreach (DirectoryInfo childDirectory in parentDirectory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly))
  {
    if (!IsIgnorable(childDirectory.Name))
    {
      DirectoryContent_Operation(childDirectory);
    }

    // Don't enter forbidden directories 
    // and optionally hidden directories too
    if (childDirectory.Attributes.HasFlag(FileAttributes.System) 
      || childDirectory.Attributes.HasFlag(FileAttributes.Hidden))
    {  
      continue;
    }
    
    // Recursively iterate over child's subdirectories
    DirectoryMainOperation(childDirectory);
  }
}

通常更喜欢 DirectoryInfo.EnumerateDirectories 而不是 DirectoryInfo.GetDirectories