0

I want to display the folder and file size in list view which is placed in my form.

Is it possible to achieve the folder size at the whole(including sub folders and files) and display it from remote computer?

With the following code, i can get the original file size, but am not all getting original folder size. Instead of it, 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() as follows :

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

I also tried with this link, but i fail because of Object reference not set to an instance of an object error when i used as,

FolderSize += (UInt64)ManagementObject2["FileSize"]; 
lvData[1] = formatSize(Convert.ToInt64 (FolderSize));

So kindly someone help me to overcome this issue.

Community
  • 1
  • 1
gkrishy
  • 756
  • 1
  • 8
  • 33
  • Is there something special with that D drive? Is it subst or is it a cd-rom drive? – rene Aug 23 '14 at 14:39
  • @rene It's just a common drive with few folders and files. And now i have been updated my question for getting possible answer. – gkrishy Aug 25 '14 at 12:43

2 Answers2

2

The problem, as @rene pointed out, is that folders don't actually have a size. They are containers. To get the total size you would have to enumerate all the files in the directory and subdirectories to calculate it.

Excerpt from MSDN

FileSize

Data type: uint64

Access type: Read-only

Size of the file system object, in bytes. Although folders possess a FileSize property, the value 0 is always returned. To determine the size of a folder, use the FileSystemObject or add up the size of all the files stored in the folder. For more information about using uint64 values in scripts, see Scripting in WMI.

The easiest way, arguably, is to use the DirectoryInfo class, UNC paths and some 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);

This will allow you get get the "total size", in bytes, for a top-level folder.

Community
  • 1
  • 1
Justin
  • 3,337
  • 3
  • 16
  • 27
  • That performs horribly and will lock up any decentbox for at least a couple of seconds, if not minutes...On the plus side, it does give the accurate value... +1 for pointing out the actual issue with the docs as reference! – rene Aug 25 '14 at 14:27
  • @rene I would agree that this isn't ideal, but if you want to calculate an arbitrary folder size, this is what you are stuck with or recursion (Async should be used in both cases). Sticking to using the drive size is a better solution. Looking back at the question, the word `folder` is used so I didn't think the user was looking for drive space. – Justin Aug 25 '14 at 14:49
  • Agreed, I can imagine a somewhere in the middle solution, mine to get a rough indication, yours iterating over the folders and file in the background to give the definitive size after a while... – rene Aug 25 '14 at 15:47
  • +1 for pointing out the exact matter in the question. But will your answer help to bring the directory or file information from remote computer ? – gkrishy Aug 26 '14 at 04:35
  • @gkrishy If you are using UNC paths and shares, yes. You may have noticed that not too many space usage utilities allow you to connect to remote machines. That is because most of the underlying tools that work with the file system are best used locally. You could use the `Win32_Directory` class, but even it isn't fun to use and you would end up with alot of WMI queries while recursing through the directories/files. – Justin Aug 26 '14 at 16:39
2

There is no size for a folder, a folder is just a container for files, the size of the files determine the foldersize.

To get the overall foldersize you can do an approximation by finding the disksize and the freespace and then subtracting those two which will give you the folder size.

On a background scan the folders with CIM_Directory and CIM_DataFile. You can call the scan method with a managementscope and a drive letter (D:)

I did run in it from a ThreadPool thread like so:

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

Iterate over folders with 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);  
}
}

Extension methods

The original code became close to unmaintainable so I implemented Extension methods for ManagementScope and 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"];
    }
}

helper for adding items to the Listview

This little helper handles switching to the UI thread if needed

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

I looked up a path selection issue in this answer from RRUZ

Community
  • 1
  • 1
rene
  • 41,474
  • 78
  • 114
  • 152
  • Is it right(also possible) to use DriveInfo class to bring the directory information from Remote Computer ? – gkrishy Aug 26 '14 at 04:33
  • Let me be more clear, I want to display directory size as well as file size which are available in some specific drive(Here it is D Drive) from remote computer. So as I said, am able to get file size, but am struggling to get folder size(directory). This function is happening in some button click, as soon as button has been clicked, list of file name and folder name will store in one column of list view, at the same time file size and folder size will store in other column of list view. – gkrishy Aug 26 '14 at 04:53
  • Everything is going good except folders size(directory). On button click event am getting exact file size but it's not happening in the case of directory rather am getting 0kb as @Justin pointed. As per your answer, i may get entire size of the directory in one line. But my question is different. Hope you may understand my question and help me to overcome. – gkrishy Aug 26 '14 at 05:09
  • For the remote computer you can only use the WMI case, DriveInfo is not gong to do that trick. – rene Aug 26 '14 at 07:21
  • Yes I knew it. And your answer will helps to get the overall used space in directory. But what i want is for individual folders in D Drive. On right click of folder, we can see the size in properties control right. Likewise, is there method to get it using c# and WQL ? – gkrishy Aug 26 '14 at 07:57
  • You can only get that information by iterating the files in that folder. – rene Aug 26 '14 at 08:46
  • Hope this will help me to solve it. As am busy with my some other works, am not able to work it out right now. So i considering this is as a correct answer. Once i tried with your work, i will let you know for further clarification. +1 for understood of my entire issue and helped me. – gkrishy Aug 27 '14 at 06:25
  • Your answer seems almost right. But I think it will show size for sub directories also. I don' want to show sub directories here but it's size should be summed up and display it. I just want to show the Main directory with entire file size which are all stored under this directory. If you don't mind can you guide me for this alone?. – gkrishy Aug 27 '14 at 11:56
  • I fixed it for you but this it. From here you're on your own. – rene Aug 27 '14 at 16:46
  • Thanks a lot for your support. – gkrishy Aug 28 '14 at 11:42