Dateigröße formatieren

    • VB.NET

    Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

      Dateigröße formatieren

      Ich hab mal eine kleine PHP-Funktion für VB umgeschrieben. Mit ihr kann man einfach Dateigrößen (wie sie z.B. IO.FileInfo.Length zurückgibt) in eine je nach Größe angepasste Einheit umwandeln.
      Unterstützt sind zurzeit Bytes, Kilobytes, Megabytes und Gigabytes.
      Bitte klicken

      VB.NET-Quellcode

      1. ''' <summary>
      2. ''' Formatiert Dateigrößen von Bytes in Bytes/Kilobytes/Megabytes/Gigabytes. Rückgabe ist eine Liste (formatierte Zahl, der Typ, in den formatiert wurde).
      3. ''' </summary>
      4. ''' <param name="size">Die zu formatierende Dateigröße</param>
      5. ''' <param name="longType">Gibt an, ob der zurückgegebene Typ der formatierten Zahl in langer Schreibweise zurückgegeben wird. (True = "Byte", False = "B")</param>
      6. ''' <param name="round">Gibt an, ob die formatierte Größe anschließend noch gerundet wird. (True = z.B. "1234.56", False = z.B. "1234.567890...")</param>
      7. ''' <param name="roundDecimals">Auf diese Dezimalstelle soll gerundet werden (wird nur beachtet, wenn der Parameter "round" auf True gesetzt ist)</param>
      8. ''' <returns></returns>
      9. ''' <remarks></remarks>
      10. Function FormatSize(ByVal size As Integer, Optional ByVal longType As Boolean = False, Optional ByVal round As Boolean = True, Optional ByVal roundDecimals As Integer = 2) As FSReturn
      11. Dim newSize As Integer = 0
      12. Dim newType As String = ""
      13. If (size < 1024) Then
      14. newSize = size
      15. If longType Then
      16. newType = "Byte"
      17. Else
      18. newType = "B"
      19. End If
      20. ElseIf (size < 1024000) Then
      21. 'return round($size/1024,2)." KB";
      22. newSize = CInt(size / 1024)
      23. If longType Then
      24. newType = "Kilobyte"
      25. Else
      26. newType = "KB"
      27. End If
      28. ElseIf (size < 1048576000) Then
      29. ' return round($size/1048576,2)." MB";
      30. newSize = CInt(size / 1048576)
      31. If longType Then
      32. newType = "Megabyte"
      33. Else
      34. newType = "MB"
      35. End If
      36. ElseIf (size < 1073741824000) Then
      37. newSize = CInt(size / 1073741824)
      38. If longType Then
      39. newType = "Gigabyte"
      40. Else
      41. newType = "GB"
      42. End If
      43. Else
      44. newSize = size
      45. If longType Then
      46. newType = "Byte"
      47. Else
      48. newType = "B"
      49. End If
      50. End If
      51. If round Then
      52. newSize = CInt(Math.Round(newSize, roundDecimals))
      53. End If
      54. Return New FSReturn(newSize, newType)
      55. End Function
      56. Structure FSReturn
      57. Public Size As Integer
      58. Public Type As String
      59. Sub New(ByVal s As Integer, ByVal t As String)
      60. Size = s
      61. Type = t
      62. End Sub
      63. End Structure

      Ein Aufruf könnte z.B. sein:

      VB.NET-Quellcode

      1. Dim fi As New IO.FileInfo(Application.ExecutablePath)
      2. Dim fs As FSReturn = FormatSize(fi.Length)
      3. Label1.Text = fs.Size & " " & fs.Type
      Mein Senf dazu: (stark verbesserungsfähig)

      VB.NET-Quellcode

      1. 'Aufruf
      2. MsgBox(makeitreadable(500))
      3. MsgBox(makeitreadable(1500))
      4. MsgBox(makeitreadable(5500))
      5. MsgBox(makeitreadable(7500))
      6. Function makeitreadable(ByVal wert As Decimal) As String
      7. Dim einheit() As String = {"Bytes", "KB", "MB", "GB", "TB"}
      8. Dim aktEinheit As Integer = 0
      9. Do While wert > 1024
      10. wert = wert / 1024
      11. aktEinheit += 1
      12. Loop
      13. Return wert.tostring & " " & einheit(aktEinheit)
      14. End Function
      Hi
      Oder so:

      VB.NET-Quellcode

      1. Public Shared Function ByteAmountToString(ByVal numberBytes As Double, ByVal digits As Integer) As String
      2. Dim value As Double = Math.Log(numberBytes, 1024.0#)
      3. Dim units() As String
      4. Dim index As Integer
      5. If value < 0.0# Then
      6. units = New String() {"B", "mB", "µB", "nB", "pB", "fB", "aB", "zB", "yB"}
      7. Else
      8. units = New String() {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
      9. End If
      10. index = Math.Min(units.Length, CInt(Math.Floor(value)))
      11. Return Math.Round(numberBytes / 1024.0# ^ index, digits).ToString & units(Math.Abs(index))
      12. End Function

      Bei niedrigen numberByte-Beträgen ist Double noch präzise. Somit kann man von der Abweichung der Digits absehen (war jetzt zu faul, das zu implementieren).

      Gruß
      ~blaze~

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ () aus folgendem Grund: Alle Zahlen zu Double verändert, die es bisher nicht waren

      Konstruktive Kritik an JU84553Hgd:
      beide gezeigten Varianten sind besser als einen identischen zusammenfassbaren Vorgang mehrmals zu wiederholen (Zeile 13-50)
      Wobei mir die Variante von ~blaze~ noch besser gefällt (hat keine Do-Loop-Schleife) :D
      @~blaze~: zu dieser Diskussion kann ich etwas beitragen. ;):

      Es gibt eine Windows-API-Funktion, um Dateigrößen zu formatieren. Sie heißt StrFormatByteSizeW.

      Verwenden kann man sie so:

      VB.NET-Quellcode

      1. <DllImport("shlwapi.dll", CharSet:=CharSet.Auto)> _
      2. Private Shared Function StrFormatByteSize(ByVal fileSize As IntPtr, ByVal buffer As StringBuilder, ByVal bufferSize As Integer) As IntPtr
      3. End Function
      4. Public Shared Function FormatByteSize(filesize As Long) As String
      5. Dim sb as New StringBuilder(25) ' 25 sollte reichen
      6. StrFormatByteSize(new IntPtr(filesize), sb, sb.Capacity)
      7. Return sb.ToString()
      8. End Function


      Hat den Vorteil, dass sie die Größe genau so formatiert, wie Windows es macht ("It's the same format as the Windows Explorer.").

      Kann man übrigens super verwenden, um einen ByteCount->String-Converter für WPF-DataBindings zu implementieren.

      -> Verschoben
      Von meinem iPhone gesendet

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „nikeee13“ ()

      Fast besser als meins, das kann ja gar nicht sein ;P. Nur die Linux-User kommen damit vmtl. nicht zurecht.

      Edit: Ich poste den Code von hier nochmal hier:

      VB.NET-Quellcode

      1. Private Shared ReadOnly _units As String() = New String() {" B", " KiB", " MiB", " GiB", " TiB", " PiB", " EiB", " ZiB", " YiB"}
      2. Public Shared Function FormatSize(ByVal size As Long) As String
      3. If size < 0 Then Throw New ArgumentOutOfRangeException("value", "Positive value or zero expected.")
      4. If size = 0 Then Return "0"c & _units(0)
      5. Dim index As Integer = Math.Min(FloorLog2(size) \ 10, _units.Length) 'Logarithmus zur Basis 1024, da log_1024 x = (log_2 x) / (log_2 1024) = (log_2 x)/10 und Abgleich mit den moeglichen Einheiten
      6. size = ((size * 100) >> (10 * index)) 'auf n Stellen genau runden ==> size * 10^n und um 1024^index nach rechts schieben
      7. If size Mod 100 = 0 Then 'gerade Werte ohne Komma darstellen (man koennte auch zwei 0-en anhaengen, also das auskommentieren)
      8. Return (size \ 100).ToString() & _units(index)
      9. Else 'sonst mit Komma darstellen
      10. Return (size \ 100).ToString() & System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator & (size Mod 100).ToString("00") & _units(index)
      11. End If
      12. End Function
      13. Public Shared Function FloorLog2(ByVal value As Long) As Integer
      14. If value <= 0 Then Throw New ArgumentOutOfRangeException("value", "Positive value expected.")
      15. Dim lower = 0, upper = 64
      16. Dim log As Integer
      17. Do
      18. log = (lower + upper) >> 1 'Mittelwert von lower und upper ermitteln
      19. Dim cv As Long = value >> log 'value um den angenommenen Logarithmus shiften
      20. If cv = 0 Then 'wenn value >> log = 0, gilt, dass log > floor(log_2 value)
      21. upper = log 'daher den oberen Wert auf log setzen
      22. ElseIf cv > 1 Then 'wenn es groesser als 1 ist, gilt, dass log < floor(log_2 value)
      23. lower = log 'daher eben den unteren Wert auf log setzen
      24. Else
      25. Exit Do 'bei = 1 ist floor(log_2 value)) berechnet worden
      26. End If
      27. Loop
      28. Return log
      29. End Function


      Gruß
      ~blaze~

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()