在.NET中查找总磁盘空间和可用空间

15

我正在尝试找到一种方法来确定.NET应用程序中任意文件夹的总磁盘空间和可用磁盘空间。在这里,所谓“文件夹的总磁盘空间”和“可用磁盘空间”,是指如果您对其执行“dir”命令,则该文件夹会报告的总磁盘空间和可用磁盘空间,即考虑到请求所在用户账户的逻辑驱动器的总体和可用磁盘空间。

我使用的是C#语言。该方法应适用于本地和远程文件夹,给定为UNC路径(而不是通过映射的驱动器字母访问)。例如,它应适用于:

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

我从一个DirectoryInfo对象开始,但似乎没有相关的磁盘空间信息。DriveInfo类有这些信息,但无法用于远程文件夹。

编辑。根据与大家的交流,我考虑将远程文件夹映射为本地驱动器,使用DriveInfo获取数据,然后再取消映射。这种方法的问题在于,我的应用程序需要每天几次收集超过120个文件夹的数据。我不确定这是否可行。

有什么建议吗?谢谢。


"available disk space in a folder" 是什么意思? - Manu
我认为他的意思是当您映射网络驱动器时,他想知道网络驱动器上有多少可用空间。 - zimmer62
1
将驱动器映射、检查空间并取消映射,这听起来多么荒谬?我意识到这不是实际的解决方案,但如果没有其他解决方案出现... - Dan Rosenstark
@yar:我考虑过那个选项,但我的应用程序需要每天几次检查120多个远程文件夹中的可用空间。你觉得那行得通吗? - CesarGon
+1 对于 map、DriveInfo 和 unmap,编写一个概念验证只需要 5 分钟的时间 - 开始吧! :-) - Duncan Smart
10个回答

14

2
正如我在原始问题中所说,DriveInfo类无法与远程文件夹一起使用。 :-) - CesarGon
抱歉CesarGon,我的错!嗯!:( 现在你指出了UNC文件夹...对不起! - t0mm13b
顺便问一下,这个可以吗?http://bytes.com/topic/net/answers/418820-space-available-remote-computer - t0mm13b
顺便说一句,George,感谢你编辑并突出了System.IO.DriveInfo!我拍了拍头 - t0mm13b
@tommieb75:嗯,真的有效!我尝试使用PInvoke调用GetDiskFreeSpaceEx(),对于本地路径和UNC路径都可以完美运行。问题解决了! - CesarGon
显示剩余2条评论

12
你可以使用{{link1:kernel32.dll中的GetDiskFreeSpaceEx}}函数,该函数可以与UNC路径和驱动器一起使用。您只需要包含一个DllImport(请参阅示例链接)。

谢谢。这正是我所做的。tommieb75在三个月前就建议过这样做! - CesarGon
@CesarGon:tommieb75提出的解决方案有点不同,因为它使用WMI对象(Windows Management Info)。结果是相同的,但您需要不同的安全设置来查询WMI对象。另一方面,DllImport也需要某些安全设置,因此这完全取决于您当前的环境。两种解决方案都可以工作并产生有效的结果。我只是添加了这个解决方案,让其他开发人员看到这个替代方案。 - user283601
tommieb75在他的初始答案中添加了一些评论。在他的评论中,他添加了一个链接到一个页面,明确展示如何使用GetDiskFreeSpaceEx()来获取总磁盘空间和可用磁盘空间。这是我实施的解决方案,也是几个月前我接受他的答案的解决方案。如果之前我表述不清楚,对不起。 :-) - CesarGon

4

这也许不是你想要的,但我在尽力帮忙,而且还有一个额外的好处,可以稍微安全地擦除您驱动器上的空闲空间。

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

1
太棒了,杰弗里。你有没有带内置流量电容器的版本呢? :p - CesarGon
1
+1 我喜欢思考一个5TB的驱动器需要多长时间,每次一个字节。很有趣。 - Dan Rosenstark
1
+1 铁锤式的解决方法,真是妙招!创意十足!! :) - Stewbob
1
谢谢大家的投票!但请不要让我成为一个干扰。有人用PInvoke或其他方法有答案吗? - Jeffrey L Whitledge

4

虽然不是C#示例,但可能会给您提示- VB.NET函数返回驱动器(以字节为单位)上指定路径的空闲和总空间的数量。与System.IO.DriveInfo不同,它也适用于UNC路径。

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

这正是我所寻找的。 - FredyWenger

1

System.IO.DriveInfo工作正常。我连接了两个不同的Netware服务器,并映射了多个驱动器。

这是本地C:驱动器:

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 

这是其中一个网络驱动器的输出结果:
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 

我使用了来自MSDN DriveInfo文档的以下代码:
using System;
using System.IO;
class Test { public static void Main() { DriveInfo[] allDrives = DriveInfo.GetDrives();
foreach (DriveInfo d in allDrives) { Console.WriteLine("驱动器 {0}", d.Name); Console.WriteLine(" 文件类型: {0}", d.DriveType); if (d.IsReady == true) { Console.WriteLine(" 卷标: {0}", d.VolumeLabel); Console.WriteLine(" 文件系统: {0}", d.DriveFormat); Console.WriteLine( " 当前用户可用空间:{0, 15} 字节", d.AvailableFreeSpace);
Console.WriteLine( " 总可用空间: {0, 15} 字节", d.TotalFreeSpace);
Console.WriteLine( " 驱动器总大小: {0, 15} 字节 ", d.TotalSize); } } } }

1
抱歉,Ken。请仔细阅读我的问题。:-) DriveInfo仅适用于本地驱动器,即使这些驱动器映射到远程文件夹。我需要一种可以直接获取未映射为本地驱动器的UNC路径的方法。感谢您的努力。 - CesarGon
1
啊,我在原帖中错过了UNC的引用。一定要更仔细地阅读。对不起,Cesar。 - Ken White
没问题,总是乐意帮忙的。 :-) - CesarGon

1

我还有一个多年来一直在使用的方法。下面的示例是VBScript,但它应该适用于任何支持COM的语言。请注意,GetDrive()也适用于UNC共享。

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
也许是因为它是用VB而不是C#编写的;但是,因为我自己讨厌匿名的负评,所以我点了个赞,把它带回到零分。 - B. Clay Shannon-B. Crow Raven
这不是我想要的,但它非常接近我所需的,所以谢谢。=) - Skotte

1
Maksim Sestic提供的答案是最好的,因为它适用于本地路径和UNC路径。我稍微修改了他的代码以获得更好的错误处理,并包括了一个示例。对我来说完美运行。
您需要放置:
Imports System.Runtime.InteropServices

将以下代码插入您的代码中,以使DllImport能够被识别。
这是修改后的代码:
<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

这样调用它:
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

文件夹名称也可以是本地目录,例如 驱动器:\路径\路径\...

它仍然是VB.NET编写的,但翻译成C#不应该有问题。


0

我刚刚将VB.NET的答案翻译成了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 _);
}

0
不是C#,只提供可用空间,但是...
dir \\server\share | find /i "bytes free"

这只是解决问题的一部分。我正在寻找相同的解决方案,但似乎没有一个好的方法 - 特别是在尝试避免映射驱动器时。


0

我非常确定这是不可能的。在Windows资源管理器中,如果我尝试获取UNC目录的文件夹属性,则不会显示可用空间。使用/可用空间是驱动器的特征,而不是文件夹,UNC共享被视为只是文件夹。

你必须要么:
- 映射驱动器
- 在远程计算机上运行某些内容以检查磁盘空间。

您还可能遇到分布式文件系统之类的问题,在其中UNC /映射共享与任何特定驱动器都没有关联,因此您必须实际上总结几个驱动器。

那么用户配额呢?驱动器可能没有满,但您用于写入该文件夹的帐户可能已达到其限制。


1
谢谢,尼尔。但是,我的Vista机器中的Windows资源管理器完全能够告诉我我正在使用的DFS文件夹中有多少可用空间。一定有一种编程方式可以做到同样的事情。 :-) - CesarGon
你是如何在资源管理器中查看可用空间的? - Neil N
@Cesar:但是XP不行。右键单击我之前发布的同一文件夹(作为UNC路径而不是映射驱动器),然后选择“属性”,我只能在对话框中看到“常规”选项卡,没有可用空间信息。相反,我看到:类型:文件夹,目标:\server\folder,创建时间:(日期和时间),注释:(无)。就只有这些了…… - Ken White
@Neil, Ken:我道歉;我看的是文件在远程文件夹中所占用的空间(大小),而不是可用空间。对于造成的困惑,我很抱歉。 - CesarGon
我可能需要在UNC路径的情况下映射驱动器,然后使用DriveInfo类。我想那应该可以解决问题。 - CesarGon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接