简体   繁体   中英

DirectoryInfo returns different values when called from different methods

I've been working on a sort of a directory info viewer. 1st stage was to create and populate a TreeView model and during coding I've nested a method to gather information about files on that dir. All worked fine, values returned we're correct etc.

Now at the stage of code cleanup when I try to get that method out of TreeView creation one I get values that are not even close to original (like 90 MB instead of 1.2 TB).

Below code with issues marked:

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)
        {
        }
    }

The gist of it is that if I invoke "DirectoryContent_Operation(directory)" from:

  1. "CreateDirectoryNode(DirectoryInfo directoryInfo)" it returns 1.2 TB (correct value)
  2. "DirectoryMainOperation(DirectoryInfo directoryInfo)" it returns 90 MB.

From what it looks like DirectoryMainOperation returns prematurely due to an UnauthorizedAccessException , hence not returning all directories. In DirectoryContent_Operation you swallow every exception by catching Exception !

Please remove the try-catch (everywhere) to see what the (inner) exception message exactly is about and where the exception is thrown..

Note that swallowing exceptions is always a code smell and will likely introduce bugs, that can be really hard to identify.
If you can't handle the exception (put the application back into a stable state) the application must crash. Then fix the reason for the crash.
Before you think about if and how to handle an exception, think about how to avoid it.
Also from a performance perspective, it is highly recommended to avoid expensive exceptions.

Your problem shows how important it is to let exceptions crash the application in order to learn about implementation errors and also to prevent unwanted silent side effects like your incomplete directory list. Swallowing exceptions has put your application into an unpredictable state, which will lead to a lot faulty behavior, which may be unnoticed by users at first. This ca be very costly for a customer who uses your application to manage his business.

To avoid the UnauthorizedAccessException in your case, you can use DirectoryInfo.EnumerateDirectories(String, EnumerationOptions) , which is available for .NET Core only (since version 2.1).
It avoids throwing an UnauthorizedAccessException exception by skipping forbidden directories by default.

Alternatively, only enumerate top level directories. Then check each child directory if it's forbidden, before you continue to recursively enumerate the child's top level directories. It is very likely that the following recursive enumeration will solve your problem.

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);
  }
}

Generally prefer DirectoryInfo.EnumerateDirectories over DirectoryInfo.GetDirectories .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM