如何在VB .NET中计算目录大小的最佳方法?

7

我需要在VB .Net中计算目录大小。

我知道以下两种方法:

方法1:来自MSDN http://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

方法二:来自.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中检查大小,只需要不到一分钟。

请建议更好、更快的方式来计算目录的大小。

9个回答

5

并行处理应该会使其更快,至少在多核机器上是这样的。请尝试以下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; 
} 

5

4

这是一个简短而有效的代码片段,可以完成任务。在调用函数之前,您只需要重置计数器即可。

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

@Magicprog.fr,循环很棒。你能告诉我在这里重置计数器的技巧是什么吗?为什么它仍然返回所有子文件夹的正确文件夹大小?我就是不明白… - LuckyLuke82
@LuckyLuke82 冒号操作符允许您在不按回车键的情况下假装有另一行,因此它会添加每个文件的大小,然后递归地添加每个子目录中的文件...尽管他们忘记将子目录的大小加入总大小:) - seadoggie01

1

非常感谢@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

0

这是我认为最好的做法。

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块来处理该问题。

0

基于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

无法编译。未定义 Interlocked - stigzler
@stigzler 它被定义在 System.Threading 中。请查看更新的答案。 - mathiasfk

0

我尽可能地简短描述一下。

它将在消息框中显示所选内容的大小。 为了使其正常工作,您需要在表单中使用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

0

尝试使用以下代码获取以GB为单位的总大小

    Dim fso = CreateObject("Scripting.FileSystemObject")
    Dim profile = fso.GetFolder("folder_path")
    MsgBox(profile.Size / 1073741824)

0
如果您只需要以字节为单位的文件夹大小,请使用以下代码:
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

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