15

I am trying to find a way to determine the total and available disk space in an arbitrary folder from a .NET app. By "total disk space" and "available disk space" in a folder I refer to the total and available disk space that this folder would report if you performed a "dir" command on it, that is, the total and available disk space of the logical drive containing that folder, considering the user account under which the request is being made.

I am using C#. The method should work both for local and remote folders given as UNC paths (rather than accessed through mapped drive letters). For example, it should work for:

  • C:\Temp
  • \\Silfen\Resources\Temp2

I am starting with a DirectoryInfo object, but this seems to have no associated disk space information. The DriveInfo class does, but it won't work with remote folders.

Edit. After some exchanges with you guys, I am considering mapping remote folders as local drives, using DriveInfo to obtain the data, and unmapping again. The problem with this approach is that my app needs to collect the data for over 120 folders a few times a day, every day. I am not sure this would be feasible.

Any ideas? Thanks.

CesarGon
  • 15,099
  • 6
  • 57
  • 85
  • What do you mean with "available disk space in a folder"? – Manu Nov 25 '09 at 21:17
  • I think he means when you map a network drive, he'd like to know how much free space is on the network drive. – zimmer62 Nov 25 '09 at 21:18
  • 1
    How ridiculous would it be to map a drive, check space, and unmap it? I realize it's not practical, but if no other solutions arise... – Dan Rosenstark Nov 25 '09 at 22:10
  • @yar: I have considered that option, but my app needs to check the available space in over 120 remote folders a few times every day. Do you think that would work? – CesarGon Nov 25 '09 at 22:13
  • +1 for the map, DriveInfo, unmap - it would only take 5 mins to code up a proof of concept - get on with it! :-) – Duncan Smart Nov 25 '09 at 22:32

10 Answers10

14

How about this link from MSDN that uses the System.IO.DriveInfo class?

George Stocker
  • 57,289
  • 29
  • 176
  • 237
t0mm13b
  • 34,087
  • 8
  • 78
  • 110
  • 2
    As I say in my original question, the DriveInfo class does not work with remote fodlers. :-) – CesarGon Nov 25 '09 at 21:21
  • Sorry CesarGon for my bad! Meh! :( Now that you pointed out UNC folders...sorry! – t0mm13b Nov 25 '09 at 21:38
  • BTW Would this do? http://bytes.com/topic/net/answers/418820-space-available-remote-computer – t0mm13b Nov 25 '09 at 21:40
  • BTW George thanks for editing it to hilight the System.IO.DriveInfo! *me slaps head* – t0mm13b Nov 25 '09 at 21:41
  • Thanks, tommieb75. From the code its seems that the WMI query just gives you the details of each logical drive on the remote machine. I would need to know what logical drive contains the UNC folder I am interested in, which is something I ignore. So no, I am afraid it won't work. :-( – CesarGon Nov 25 '09 at 21:45
  • @tommieb75: Well, that really works! I have tried calling GetDiskFreeSpaceEx() using pinvoke and it works flawlessly for local and UNC paths. Problem solved! – CesarGon Nov 25 '09 at 23:59
  • @CesarGon: Delighted to hear! :) – t0mm13b Nov 26 '09 at 00:10
12

You can use GetDiskFreeSpaceEx from kernel32.dll which works with UNC-paths and drives. All you need to do is include a DllImport (see link for an example).

  • Thanks. That's exactly what I did. :-) tommieb75 above suggested it over three months ago! – CesarGon Mar 02 '10 at 02:36
  • @CesarGon: The solution tommieb75 suggested is a bit different, because it uses WMI-objects (Windows Management Info). The result is the same, but you need different security-settings to query WMI-objects. On the other hand, DllImport also needs certain security-settings, so it all depends on your current environment. Both solutions can work and produce valid results. I just added this solution for other developers to see the alternative. –  Mar 02 '10 at 12:02
  • tommieb75 added a few comments to his initial answer. In his comments, he adds a link to a page that explicitly shows how to use GetDiskFreeSpaceEx() to obtain the total and free disk space. This is the solution that I implemented, and this is the solution for which I accepted his answer months ago. Sorry if I wasn't clear before. :-) – CesarGon Mar 03 '10 at 19:12
4

This may not be what you want, but I'm trying to help, and it has the bonus of slightly secure erasing the free space of your drive.

public static string DriveSizeAvailable(string path)
{
    long count = 0;
    byte toWrite = 1;
    try
    {
        using (StreamWriter writer = new StreamWriter(path))
        {
            while (true)
            {
                writer.Write(toWrite);
                count++;
            }
        }
    }
    catch (IOException)
    {                
    }

    return string.Format("There used to be {0} bytes available on drive {1}.", count, path);
}

public static string DriveSizeTotal(string path)
{
    DeleteAllFiles(path);
    int sizeAvailable = GetAvailableSize(path);
    return string.Format("Drive {0} will hold a total of {1} bytes.", path, sizeAvailable);
}
Matthew Lock
  • 13,144
  • 12
  • 92
  • 130
Jeffrey L Whitledge
  • 58,241
  • 9
  • 71
  • 99
4

Not really a C# example but may give you a hint - a VB.NET function returning both amount of free and total space on drive (in bytes) along specified path. Works for UNC paths as well, unlike System.IO.DriveInfo.

VB.NET:

<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function GetDiskFreeSpaceEx(lpDirectoryName As String, ByRef lpFreeBytesAvailable As ULong, ByRef lpTotalNumberOfBytes As ULong, ByRef lpTotalNumberOfFreeBytes As ULong) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

Public Shared Function GetDriveSpace(folderName As String, ByRef freespace As ULong, ByRef totalspace As ULong) As Boolean
    If Not String.IsNullOrEmpty(folderName) Then
        If Not folderName.EndsWith("\") Then
            folderName += "\"
        End If

        Dim free As ULong = 0, total As ULong = 0, dummy2 As ULong = 0
        If GetDiskFreeSpaceEx(folderName, free, total, dummy2) Then
            freespace = free
            totalspace = total
            Return True
        End If
    End If
End Function
Maksim Sestic
  • 300
  • 2
  • 8
1

Here's one more possibility that I've used for years. The example below is VBScript, but it should work with any COM-aware language. Note that GetDrive() works on UNC shares as well.

Dim Tripped
Dim Level

Tripped = False
Level   = 0

Sub Read(Entry, Source, SearchText, Minimum, Maximum)

    Dim fso
    Dim disk

    Set fso  = CreateObject("Scripting.FileSystemObject")

    Set disk = fso.GetDrive(Source)

    Level = (disk.AvailableSpace / (1024 * 1024 * 1024))

    If (CDbl(Level) < CDbl(Minimum)) or (CDbl(Level) > CDbl(Maximum)) Then
        Tripped = True
    Else
        Tripped = False
    End If

End Sub
CrazyIvan1974
  • 377
  • 1
  • 2
  • 11
1

System.IO.DriveInfo works fine. I'm attached to two separate Netware servers, with several drives mapped.

Here's for the local C: drive:

Drive C:\
  File type: Fixed
  Volume label: Drive C
  File system: NTFS
  Available space to current user:   158558248960 bytes
  Total available space:             158558248960 bytes
  Total size of drive:               249884004352 bytes 

Here's the output for one of the network drives:

Drive F:\
  File type: Network
  Volume label: SYS
  File system: NWFS
  Available space to current user:     1840656384 bytes
  Total available space:               1840656384 bytes
  Total size of drive:                 4124475392 bytes 

I used the following code, directly from the MSDN docs on DriveInfo:

using System;
using System.IO;

class Test
{
    public static void Main()
    {
        DriveInfo[] allDrives = DriveInfo.GetDrives();

        foreach (DriveInfo d in allDrives)
        {
            Console.WriteLine("Drive {0}", d.Name);
            Console.WriteLine("  File type: {0}", d.DriveType);
            if (d.IsReady == true)
            {
                Console.WriteLine("  Volume label: {0}", d.VolumeLabel);
                Console.WriteLine("  File system: {0}", d.DriveFormat);
                Console.WriteLine(
                    "  Available space to current user:{0, 15} bytes", 
                    d.AvailableFreeSpace);

                Console.WriteLine(
                    "  Total available space:          {0, 15} bytes",
                    d.TotalFreeSpace);

                Console.WriteLine(
                    "  Total size of drive:            {0, 15} bytes ",
                    d.TotalSize);
            }
        }
    }
}
Ken White
  • 123,280
  • 14
  • 225
  • 444
  • 1
    Sorry, Ken. Please read my question carefully. :-) DriveInfo works on local drives only, even when these are mapped to remote folders. I need a method that can take UNC paths directly that are not mapped as local drives. Thanks for your effort though. – CesarGon Nov 25 '09 at 21:24
  • 1
    Ah, I missed the UNC reference in the original post. *Must* read more carefully. Sorry, Cesar. – Ken White Nov 25 '09 at 21:28
  • No problem; help is always appreciated. :-) – CesarGon Nov 25 '09 at 21:31
1

Maksim Sestic has given the best answer, as it works on both, local and UNC paths. I have changed his code a little for better error handling and included an example. Works for me like a charm.

You need to put

Imports System.Runtime.InteropServices

into your code, to allow DllImport to be recognized.

Here is the modified code:

<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function GetDiskFreeSpaceEx(lpDirectoryName As String, ByRef lpFreeBytesAvailable As ULong, ByRef lpTotalNumberOfBytes As ULong, ByRef lpTotalNumberOfFreeBytes As ULong) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

Public Shared Function GetDriveSpace(folderName As String, ByRef freespace As ULong, ByRef totalspace As ULong) As Boolean

Dim free As ULong = 0
Dim total As ULong = 0
Dim dummy2 As ULong = 0

Try

    If Not String.IsNullOrEmpty(folderName) Then

         If Not folderName.EndsWith("\") Then
             folderName += "\"
         End If

         If GetDiskFreeSpaceEx(folderName, free, total, dummy2) Then
             freespace = free
             totalspace = total
             Return True
         End If

     End If

Catch
End Try

    Return False

End Function

Call it this way:

dim totalspace as ulong = 0
dim freespace as ulong = 0
if GetDriveSpace("\\anycomputer\anyshare", freespace, totalspace) then
    'do what you need to do with freespace and totalspace
else
    'some error
end if

The foldername can also be a local directory like drive:\path\path\...

It is still in VB.NET but shouldn't be a problem to translate into C#.

Herbert
  • 151
  • 2
  • 12
0

I'm pretty sure this is impossible. In windows explorer, if I try to get the folder properties of a UNC directory, it gives me nothing as far as available space. Used/Available space is a characteristic of drives, not folders, and UNC shares are treated as just folders.

you have to either:
- Map a drive
- Run something on the remote machine to check disk space.

You could also run into problems with something like Distributed file system, in which a UNC/Mapped share is NOT tied to any specific drive, so there youd have to actually sum up several drives.

And what about user quotas? The drive may not be full, but the account you are using to write to that folder may have hit its limit.

Neil N
  • 24,862
  • 16
  • 85
  • 145
  • 1
    Thanks, Neil. But then again, the Windows Explorer in my Vista machine is perfectly capable of telling me how much space there is available in a DFS folder I am using. There must be a way to programmaticaly do the same thing. :-) – CesarGon Nov 25 '09 at 21:39
  • How exactly are you seeing the space availble in explorer? – Neil N Nov 25 '09 at 21:46
  • @Cesar: But XP can't. Right-clicking the same folder (as a UNC path instead of mapped drive) I posted before and choosing "Properties", I get just the "General" tab in the dialog with no free space info. Instead, I see: Type: Folder Target: \\server\folder, Created: (date and time), Comment: (nothing). That's all there is... – Ken White Nov 25 '09 at 21:49
  • @Neil, Ken: I apologise; I was looking at the space that files occupy in the remote folder (Size), not to the available size. Sorry about the confusion. – CesarGon Nov 25 '09 at 22:11
  • I might have to map a drive in the case of UNC paths and then use the DriveInfo class. That would work I guess. – CesarGon Nov 25 '09 at 22:12
0

Not C# and only gives the avilable space, but . . .

dir \\server\share | find /i "bytes free"

gets you part of the way. I'm looking or the same solution but there doesn't seem to be a nice one - especially when trying to avoid mapping drives.

Mike
  • 129
  • 3
0

I just translated VB.NET answers to C#:

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool GetDiskFreeSpaceEx(string lpDirectoryName, out ulong lpFreeBytesAvailable, out ulong lpTotalNumberOfBytes, out ulong lpTotalNumberOfFreeBytes);

public static bool GetDriveSpace(string folderName, out ulong freespace, out ulong totalspace)
{
    if (string.IsNullOrEmpty(folderName)) throw new ArgumentNullException(nameof(folderName));
    if (folderName[^1] != '\\') folderName += '\\';
    return GetDiskFreeSpaceEx(folderName, out freespace, out totalspace, out _);
}
palota
  • 465
  • 4
  • 8