It seems that using WMI to query the filesystem is very slow when using the LIKE
operator to filter on the Name
/Path
property, even if the filter value doesn't contain a wildcard (%
).
This will take more than one query, but you can get the CIM_Directory
(actually Win32_Directory
) instance for your base directory and traverse the hierarchy yourself...
static void EnumerateDirectory(ManagementObject directory, bool recurse)
{
// Get all related CIM_LogicalFile instances where this is the parent (GroupComponent)
// and the related instance is the child (PartComponent)
using (ManagementObjectCollection children = directory.GetRelated("CIM_LogicalFile", null, null, null, "PartComponent", "GroupComponent", false, null))
foreach (ManagementObject child in children.Cast<ManagementObject>())
switch (child.Path.ClassName)
{
case "CIM_Directory":
case "Win32_Directory":
Console.WriteLine($"Directory: { child["Name"] }");
if (recurse)
EnumerateDirectory(child, true);
break;
case "CIM_DataFile":
Console.WriteLine($" File: { child["Name"] }");
break;
default:
Console.WriteLine($"ERROR: Unexpected { child.Path.ClassName } instance. This should never happen!");
break;
}
}
That's calling GetRelated()
to get all CIM_LogicalFile
instances associated with directory
; CIM_LogicalFile
is the parent class of CIM_DataFile
and CIM_Directory
, which itself is the parent of Win32_Directory
. We could call the simpler directory.GetRelated("CIM_LogicalFile")
overload but that would return one CIM_Directory
instance we don't want: the parent directory. Instead, we call that longer overload that allows us to specify that we want directory
to be the parent in the CIM_Directory
⇔ CIM_Directory
relationship.
You would call EnumerateDirectory()
like this...
static void Main()
{
const string directoryPath = @"C:\YC";
ObjectQuery directoryQuery = new SelectQuery(
"CIM_Directory",
$"Name = \"{ directoryPath.Replace(@"\", @"\\") }\""
);
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(directoryQuery))
using (ManagementObjectCollection results = searcher.Get())
using (ManagementObject directory = results.Cast<ManagementObject>().SingleOrDefault())
{
if (directory == null)
Console.WriteLine($"ERROR: The query ' { directoryQuery.QueryString } ' returned no results.");
else
EnumerateDirectory(directory, true);
}
}
If you only want the immediate child files in a directory that code is much simpler...
static void EnumerateFiles(ManagementObject directory)
{
using (ManagementObjectCollection children = directory.GetRelated("CIM_DataFile"))
foreach (ManagementObject child in children.Cast<ManagementObject>())
Console.WriteLine($"File: { child["Name"] }");
}