我需要在 VB .Net 中计算目录大小
我知道以下2个方法
方法一:来自MSDNhttp://msdn.microsoft.com/en-us/library/system.io.directory.aspx
' 下面例子计算一个目录的大小 ' 及其子目录(如果有)并显示总大小 ' 以字节为单位。
Imports System
Imports System.IO
Public Class ShowDirSize
Public Shared Function DirSize(ByVal d As DirectoryInfo) As Long
Dim Size As Long = 0
' Add file sizes.
Dim fis As FileInfo() = d.GetFiles()
Dim fi As FileInfo
For Each fi In fis
Size += fi.Length
Next fi
' Add subdirectory sizes.
Dim dis As DirectoryInfo() = d.GetDirectories()
Dim di As DirectoryInfo
For Each di In dis
Size += DirSize(di)
Next di
Return Size
End Function 'DirSize
Public Shared Sub Main(ByVal args() As String)
If args.Length <> 1 Then
Console.WriteLine("You must provide a directory argument at the command line.")
Else
Dim d As New DirectoryInfo(args(0))
Dim dsize As Long = DirSize(d)
Console.WriteLine("The size of {0} and its subdirectories is {1} bytes.", d, dsize)
End If
End Sub 'Main
End Class 'ShowDirSize
方法 2:来自 在 .NET 中计算目录大小的最佳方法是什么?
Dim size As Int64 = (From strFile In My.Computer.FileSystem.GetFiles(strFolder, _
FileIO.SearchOption.SearchAllSubDirectories) _
Select New System.IO.FileInfo(strFile).Length).Sum()
这两种方法都很好用。但是,如果有很多子文件夹,它们会花费很多时间来计算目录大小。例如,我有一个包含 150,000 个子文件夹的目录。上述方法花费了大约 1 小时 30 分钟来计算目录的大小。但是,如果我从 Windows 检查大小,只需不到一分钟。
请建议更好更快的计算目录大小的方法。
虽然这个答案是在谈论Python,但这个概念也适用于这里。
Windows资源管理器使用系统API调用
FindFirstFile
和FindNextFile
递归地拉取文件信息,然后可以通过struct
,WIN32_FIND_DATA
传回的数据非常快速地访问文件大小:http:// msdn.microsoft.com/en-us/library/aa365740(v=VS.85).aspx.
我的建议是使用 P/Invoke 实现这些 API 调用,我相信您会体验到显着的性能提升。
并行工作应该会更快,至少在多核机器上是这样。试试这个 C# 代码。你必须翻译 VB.NET.
private static long DirSize(string sourceDir, bool recurse)
{
long size = 0;
string[] fileEntries = Directory.GetFiles(sourceDir);
foreach (string fileName in fileEntries)
{
Interlocked.Add(ref size, (new FileInfo(fileName)).Length);
}
if (recurse)
{
string[] subdirEntries = Directory.GetDirectories(sourceDir);
Parallel.For<long>(0, subdirEntries.Length, () => 0, (i, loop, subtotal) =>
{
if ((File.GetAttributes(subdirEntries[i]) & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint)
{
subtotal += DirSize(subdirEntries[i], true);
return subtotal;
}
return 0;
},
(x) => Interlocked.Add(ref size, x)
);
}
return size;
}
这是一个简短而有趣的代码片段,可以完成工作。您只需要在调用函数之前重置计数器
Public Class Form1
Dim TotalSize As Long = 0
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
TotalSize = 0 'Reset the counter
Dim TheSize As Long = GetDirSize("C:\Test")
MsgBox(FormatNumber(TheSize, 0) & " Bytes" & vbCr & _
FormatNumber(TheSize / 1024, 1) & " Kilobytes" & vbCr & _
FormatNumber(TheSize / 1024 / 1024, 1) & " Megabytes" & vbCr & _
FormatNumber(TheSize / 1024 / 1024 / 1024, 1) & " Gigabytes")
End Sub
Public Function GetDirSize(RootFolder As String) As Long
Dim FolderInfo = New IO.DirectoryInfo(RootFolder)
For Each File In FolderInfo.GetFiles : TotalSize += File.Length
Next
For Each SubFolderInfo In FolderInfo.GetDirectories : GetDirSize(SubFolderInfo.FullName)
Next
Return TotalSize
End Function
End Class
非常感谢@Jamie 的代码和@Mathiasfk 对 VB.net 的翻译。我将它用于我自己的备份程序,在默认设置下只备份整个配置文件文件夹,它是一个最终也能够理解连接点并读取或多或少正确大小的代码。至少备份没问题。 :-)
我只需要将代码放在 Try 中,这样它就不会因无法访问的文件夹而停止,如果您也可能遇到这样的问题,请使用它(不处理错误只是跳过它,您可以添加如果对你很重要):
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Public Function GetFolderSize(ByVal path As String, Optional recurse As Boolean = True) As Long
Dim totalSize As Long = 0
Try
Dim files() As String = Directory.GetFiles(path)
Parallel.For(0, files.Length,
Sub(index As Integer)
Dim fi As New FileInfo(files(index))
Dim size As Long = fi.Length
Interlocked.Add(totalSize, size)
End Sub)
Catch ex As Exception
End Try
Try
If recurse Then
Dim subDirs() As String = Directory.GetDirectories(path)
Dim subTotal As Long = 0
Parallel.For(0, subDirs.Length,
Function(index As Integer)
If (File.GetAttributes(subDirs(index)) And FileAttributes.ReparsePoint) <> FileAttributes.ReparsePoint Then
Interlocked.Add(subTotal, GetFolderSize(subDirs(index), True))
Return subTotal
End If
Return 0
End Function)
Interlocked.Add(totalSize, subTotal)
End If
Catch ex As Exception
End Try
Return totalSize
End Function
这里尽可能简短。
它将在消息框中显示所选内容的大小。 您将需要在表格中使用
FolderBrowserDialog
才能正常工作。
Class Form1
Private Sub form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
If (FolderBrowserDialog1.ShowDialog() = DialogResult.OK) Then
Else : End
End If
Dim dInfo As New IO.DirectoryInfo(FolderBrowserDialog1.SelectedPath)
Dim sizeOfDir As Long = DirectorySize(dInfo, True)
MsgBox("Showing Directory size of " & FolderBrowserDialog1.SelectedPath _
& vbNewLine & "Directory size in Bytes : " & "Bytes " & sizeOfDir _
& vbNewLine & "Directory size in KB : " & "KB " & Math.Round(sizeOfDir / 1024, 3) _
& vbNewLine & "Directory size in MB : " & "MB " & Math.Round(sizeOfDir / (1024 * 1024), 3) _
& vbNewLine & "Directory size in GB : " & "GB " & Math.Round(sizeOfDir / (1024 * 1024 * 1024), 3))
Catch ex As Exception
End Try
End Sub
Private Function DirectorySize(ByVal dInfo As IO.DirectoryInfo, ByVal includeSubDir As Boolean) As Long
Dim totalSize As Long = dInfo.EnumerateFiles().Sum(Function(file) file.Length)
If includeSubDir Then totalSize += dInfo.EnumerateDirectories().Sum(Function(dir) DirectorySize(dir, True))
Return totalSize
End Function
End Class
基于 Jamie 回答的 VB 代码:
Imports System.Threading
Imports System.IO
Public Function GetDirectorySize(ByVal path As String, Optional recurse As Boolean = False) As Long
Dim totalSize As Long = 0
Dim files() As String = Directory.GetFiles(path)
Parallel.For(0, files.Length,
Sub(index As Integer)
Dim fi As New FileInfo(files(index))
Dim size As Long = fi.Length
Interlocked.Add(totalSize, size)
End Sub)
If recurse Then
Dim subDirs() As String = Directory.GetDirectories(path)
Dim subTotal As Long = 0
Parallel.For(0, subDirs.Length,
Function(index As Integer)
If (File.GetAttributes(subDirs(index)) And FileAttributes.ReparsePoint) <> FileAttributes.ReparsePoint Then
Interlocked.Add(subTotal, GetDirectorySize(subDirs(index), True))
Return subTotal
End If
Return 0
End Function)
Interlocked.Add(totalSize, subTotal)
End If
Return totalSize
End Function
试试这个以获得以 GB 为单位的总大小
Dim fso = CreateObject("Scripting.FileSystemObject")
Dim profile = fso.GetFolder("folder_path")
MsgBox(profile.Size / 1073741824)
这是我认为最好的方法。
Imports System.IO
Public Class FolderSizeCalculator
Public Shared Function GetFolderSize(ByVal folderPath As String) As Long
Dim size As Long = 0
Try
Dim files As String() = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories)
For Each file As String In files
Dim fileInfo As New FileInfo(file)
size += fileInfo.Length
Next
Catch ex As Exception
' Handle any exceptions that may occur
End Try
Return size
End Function
End Class
您可以调用GetFolderSize()方法并传入您要计算其大小的文件夹的路径,它将以字节为单位返回大小。
你可以这样使用它:
Dim folderSize As Long = FolderSizeCalculator.GetFolderSize("C:\MyFolder")
Console.WriteLine("Folder size: " & folderSize & " bytes")
..请注意,如果运行应用程序的用户没有读取文件夹或子文件夹的权限,此方法将失败,您可以使用 try catch 块处理该问题
如果您只需要以字节为单位的文件夹大小,请使用:
Public Function GetFolderSize(TargetFolder As String) As ULong
Dim DirObject As New IO.DirectoryInfo(TargetFolder)
Dim FolderBytes As ULong = 0
For Each FileObject As IO.FileInfo In DirObject.GetFiles
FolderBytes += FileObject.Length
Next
For Each NextDir As IO.DirectoryInfo In DirObject.GetDirectories
FolderBytes += GetFolderSize(NextDir.FullName)
Next
Return FolderBytes
End Function
如果你想要一个更易于阅读的字符串,也可以添加这些函数:
' Example: Console.WriteLine(ForHumans(GetFolderSize(TargetFolder))
Public Function ForHumans(ByteSize As ULong) As String
Dim OneKB As ULong = 2 ^ 10
Dim OneMB As ULong = 2 ^ 20
Dim OneGB As ULong = 2 ^ 30
Dim OneTB As ULong = 2 ^ 40
Dim TwentyKB As ULong = OneKB * 20
Dim TwentyMB As ULong = OneMB * 20
Dim TwentyGB As ULong = OneGB * 20
Dim TwentyTB As ULong = OneTB * 20
If ByteSize > TwentyTB Then
Return AddCommas(ByteSize \ OneTB) & " TB"
ElseIf ByteSize > TwentyGB Then
Return AddCommas(ByteSize \ OneGB) & " GB"
ElseIf ByteSize > TwentyMB Then
Return AddCommas(ByteSize \ OneMB) & " MB"
ElseIf ByteSize > TwentyKB Then
Return AddCommas(ByteSize \ OneKB) & " KB"
Else
Return AddCommas(ByteSize) & " bytes"
End If
End Function
Public Function AddCommas(InputNumber As ULong) As String
Dim I As String = InputNumber.ToString
If I.Length > 6 Then
Return I.Substring(0, I.Length - 6) & "," & I.Substring(I.Length - 6, 3) & "," & I.Substring(I.Length - 3)
ElseIf I.Length > 3 Then
Return I.Substring(0, I.Length - 3) & "," & I.Substring(I.Length - 3)
Else
Return I
End If
End Function