【问题标题】:Is there a faster way to query a remote filesystem with WMI?有没有更快的方法来使用 WMI 查询远程文件系统?
【发布时间】:2021-12-09 08:36:44
【问题描述】:

我试图递归地获取目录C:\YC 下的所有文件——5 或 6 个文件。我被绑定到对远程计算机的一次 WMI 调用。

我设法使用 WQL LIKE 运算符执行此调用,但它需要大约 30 秒,即使结果是大约 6 个文件:

// USING A WQL QUERY
string query = "SELECT Name,LastModified FROM CIM_DataFile WHERE PATH LIKE '\\\\YC\\\\%' AND DRIVE ='C:'";
ObjectQuery oQuery = new ObjectQuery();
oQuery.QueryString = query;

ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(scope, oQuery);
oSearcher.Options.Rewindable = false;

// Takes long time
ManagementObjectCollection oReturnCollection = oSearcher.Get();

// SHOWING EACH FILE
foreach (ManagementObject oReturn in oReturnCollection)
{
     Console.WriteLine(oReturn["Name"]?.ToString());
}

有没有更有效的方法使用System.Management 对象递归地获取文件(使用或不使用 WQL,但使用一次 WMI 调用)?

【问题讨论】:

    标签: c# .net wmi directory-listing system.management


    【解决方案1】:

    使用LIKE 运算符过滤Name/Path 属性时,使用WMI 查询文件系统似乎非常慢,即使过滤器值不包含通配符(% )。

    这需要不止一个查询,但您可以获取基本目录的CIM_Directory(实际上是Win32_Directory)实例并自己遍历层次结构...

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

    调用GetRelated() 获取所有CIM_LogicalFile 实例associated with directoryCIM_LogicalFileCIM_DataFileCIM_Directory 的父类,而CIM_Directory 本身就是Win32_Directory 的父类。我们可以调用更简单的directory.GetRelated("CIM_LogicalFile") 重载,但这会返回一个我们不想要的CIM_Directory 实例:父目录。相反,我们称之为更长的重载,它允许我们指定我们希望 directory 成为 CIM_DirectoryCIM_Directory 关系中的父级。

    你会像这样打电话给EnumerateDirectory()...

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

    如果您只想要目录中的直接子文件,那么代码要简单得多......

    static void EnumerateFiles(ManagementObject directory)
    {
        using (ManagementObjectCollection children = directory.GetRelated("CIM_DataFile"))
            foreach (ManagementObject child in children.Cast<ManagementObject>())
                Console.WriteLine($"File: { child["Name"] }");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2010-12-29
      • 2013-10-10
      相关资源
      最近更新 更多