如何使用wql在c#中实现文件夹大小属性?

时间:2014-08-23 12:21:11

标签: c# .net listview wmi wql

我想在列表视图中显示文件夹和文件大小,该文件放在我的表单中。

是否可以在整体上实现文件夹大小(包括子文件夹和文件)并从远程计算机显示?

使用以下代码,我可以获得原始文件大小,但并非所有原始文件夹大小。而不是am getting folder size as 0kb

ManagementScope ManagementScope1 = new ManagementScope(string.Format("\\\\{0}\\root\\cimv2", strIP), options);
ManagementScope1.Connect();
ObjectGetOptions objectGetOptions = new ObjectGetOptions();
ObjectQuery obq1 = new ObjectQuery("Associators of {Win32_Directory.Name='D:'} Where ResultRole = PartComponent ");
ManagementObjectSearcher searcher1 = new ManagementObjectSearcher(ManagementScope1, obq1);

foreach (ManagementObject ManagementObject2 in searcher1.Get())
{
    lvData[0] = ManagementObject2["FileName"].ToString();
    lvData[1] = formatSize(Convert.ToInt64(ManagementObject2["FileSize"]));
    ListViewItem lvItem = new ListViewItem(lvData, 0);
    lvFiles.Items.Add(lvItem);
}

formatSize()如下:

protected string formatSize(Int64 lSize)
{
        //Format number to KB
     string stringSize = "";
     NumberFormatInfo myNfi = new NumberFormatInfo();

     Int64 lKBSize = 0;

     if (lSize < 1024)
     {
         if (lSize == 0)
         {
            //zero byte
            stringSize = "0";
         }
         else
         {
            //less than 1K but not zero byte
            stringSize = "1";
         }
      }
      else
      {
            //convert to KB
            lKBSize = lSize / 1024;
            //format number with default format
            stringSize = lKBSize.ToString("n", myNfi);
            //remove decimal
            stringSize = stringSize.Replace(".00", "");
      }
      return stringSize + " KB";
 }

我也尝试了这个link,但是由于对象引用没有设置为对象的实例错误,当我用作

时,我失败了
FolderSize += (UInt64)ManagementObject2["FileSize"]; 
lvData[1] = formatSize(Convert.ToInt64 (FolderSize));

亲切地帮助我克服这个问题。

2 个答案:

答案 0 :(得分:2)

正如@rene指出的那样,问题在于文件夹实际上没有大小。它们是容器。要获得总大小,您必须枚举目录和子目录中的所有文件以进行计算。

摘自MSDN

  

<强>文件大小

     

数据类型: uint64

     

访问类型:只读

     

文件系统对象的大小,以字节为单位。 虽然文件夹具有FileSize属性,但始终返回值0。要确定文件夹的大小,请使用FileSystemObject或添加文件夹中存储的所有文件的大小。   有关在脚本中使用uint64值的更多信息,请参阅WMI中的脚本。

可以说,最简单的方法是使用DirectoryInfo类,UNC路径和一些LINQ。

var folder = @"\\MachineOrIp\c$\Temp";

        var directory = new DirectoryInfo(folder);
        var totalSize = directory.EnumerateFiles("*.*", SearchOption.AllDirectories).Sum(file => file.Length);

        Console.WriteLine("{0} - {1} Bytes", folder, totalSize);

这样您就可以获得顶级文件夹的&#34;总大小&#34;(以字节为单位)。

答案 1 :(得分:2)

文件夹没有大小,文件夹只是文件的容器,文件的大小决定了文件夹大小。

要获得整体文件夹大小,您可以通过查找磁盘大小和自由空间然后减去那两个将为您提供文件夹大小的近似值。

在后台使用CIM_DirectoryCIM_DataFile扫描文件夹。您可以使用管理范围和驱动器号(D:)

调用扫描方法

我确实从ThreadPool线程中运行过它:

ManagementScope ManagementScope1 = new ManagementScope();
ManagementScope1.Connect();
ThreadPool.QueueUserWorkItem((que) => { scan(ManagementScope1, "D:"); });

使用WMI

迭代文件夹
private void scan(ManagementScope scope, string drive)
{
var disk = scope.Device(drive).GetEnumerator();
if (!disk.MoveNext())
{
    Add(String.Format("{0} drive not found",drive),0);
    return;
}

Add(drive, disk.Current.Size() - disk.Current.FreeSpace());

// iterate over root Folders
foreach (var folder in scope.Folder(drive))
{
    ulong totalsize = 0;
    try
    {
        // iterate over the files
        foreach (var file in scope.File(
                    drive,
                    folder.Path(),
                    folder.FileName()))
        {
            totalsize += file.FileSize();
        }
        // iterate over all subfolders
        foreach (var subfolder in scope.SubFolder(drive
                    , folder.Path()
                    , folder.FileName()))
        {
            // iterate over files within a folder
            foreach (var file in scope.File(
                    drive,
                    subfolder.Path(),
                    subfolder.FileName()))
            {
                totalsize += file.FileSize();
            }
        }
    }
    catch (Exception exp)
    {
        Debug.WriteLine(exp.Message);
    }
    Add(folder.Name(), totalsize);  
}
}

扩展方法

原始代码变得接近无法维护,因此我为ManagementScope和ManagementBaseObject实现了扩展方法。

public static class ManagementObjectExtensions
{
    const string WQL_DEVICE = "Select Size,FreeSpace from Win32_LogicalDisk where Deviceid='{0}'";
    const string WQL_FOLDER = "Select Path, Filename, Name from CIM_Directory where Drive='{0}' and path='\\\\' and system = false and hidden = false and readable = true";
    const string WQL_SUBFOLDER = "Select Path, Filename from CIM_Directory where Drive='{0}' and path like '{1}{2}\\\\%' and system = false and hidden = false and readable = true";
    const string WQL_FILE = "Select FileSize from CIM_DataFile where Drive='{0}' AND Path = '{1}{2}\\\\' ";

    // internal helper to get an enumerable collection from any WQL
    private static ManagementObjectCollection GetWqlEnumerator(this ManagementScope scope, string wql, params object[] args)
    {
        return new ManagementObjectSearcher(
            scope,
            new ObjectQuery(
                String.Format(wql, args)))
            .Get();
    }

    public static ManagementObjectCollection Device(this ManagementScope scope, params object[] args)
    {
        return scope.GetWqlEnumerator(WQL_DEVICE, args);
    }

    public static ManagementObjectCollection Folder(this ManagementScope scope, params object[] args)
    {
        return scope.GetWqlEnumerator(WQL_FOLDER, args);
    }

    public static ManagementObjectCollection SubFolder(this ManagementScope scope, params object[] args)
    {
        return scope.GetWqlEnumerator(WQL_SUBFOLDER, args);
    }

    public static ManagementObjectCollection File(this ManagementScope scope, params object[] args)
    {
        return scope.GetWqlEnumerator(WQL_FILE, args);
    }

    public static string Path(this ManagementBaseObject mo)
    {
        return mo["Path"].ToString().Replace("\\","\\\\");
    }

    public static string Name(this ManagementBaseObject mo)
    {
        return mo["Name"].ToString();
    }

    public static string FileName(this ManagementBaseObject mo)
    {
        return mo["FileName"].ToString();
    }

    public static ulong FreeSpace(this ManagementBaseObject mo)
    {
        return (ulong)mo["FreeSpace"];
    }

    public static ulong Size(this ManagementBaseObject mo)
    {
        return (ulong) mo["Size"];
    }

    public static ulong FileSize(this ManagementBaseObject mo)
    {
        return (ulong) mo["FileSize"];
    }
}

帮助将项目添加到Listview

如果需要,这个小助手会处理切换到UI线程

// UI Thread safe helper for adding an item
private void Add(string name, ulong size)
{
    if (this.listView1.InvokeRequired)
    {
        this.listView1.Invoke(new MethodInvoker(() => Add(name, size)));
    }
    else
    {
        var lvi = new ListViewItem(name);
        lvi.SubItems.Add(size.ToString());

        this.listView1.Items.Add(lvi);
    }
}

我在this answer

RRUZ中查找了路径选择问题