Wie erhalte ich mit .NET eine für Menschen lesbare Dateigröße in Byte-Abkürzung?

Antworten:

353

Dies ist nicht der effizienteste Weg, aber es ist einfacher zu lesen, wenn Sie nicht mit Protokollmathematik vertraut sind und für die meisten Szenarien schnell genug sein sollten.

string[] sizes = { "B", "KB", "MB", "GB", "TB" };
double len = new FileInfo(filename).Length;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1) {
    order++;
    len = len/1024;
}

// Adjust the format string to your preferences. For example "{0:0.#}{1}" would
// show a single decimal place, and no space.
string result = String.Format("{0:0.##} {1}", len, sizes[order]);
David Thibault
quelle
12
Ich glaube, Sie könnten Math.Log verwenden, um die Reihenfolge zu bestimmen, anstatt eine while-Schleife zu verwenden.
Francois Botha
12
Außerdem beträgt KB 1000 Byte. 1024 Bytes sind KiB .
Constantin
12
@Constantin gut das hängt vom Betriebssystem ab? Windows zählt immer noch 1024 Bytes als 1 KB und 1 MB = 1024 KB. Ich persönlich möchte das KiB aus dem Fenster werfen und einfach alles mit 1024 zählen? ...
Peter
4
@Petoj es hängt nicht vom Betriebssystem ab, die Definition ist OS-unabhängig. Aus Wikipedia:The unit was established by the International Electrotechnical Commission (IEC) in 1998 and has been accepted for use by all major standards organizations
ANeves
3
Ich bevorzuge den Code, da er schneller zu laufen scheint, aber ich habe ihn leicht modifiziert, um eine unterschiedliche Anzahl von Dezimalstellen zuzulassen. Kleinere Zahlen zeigen besser 2 Dezimalstellen, z. B. 1,38 MB, während größere Zahlen weniger Dezimalstellen erfordern, z. B. 246 KB oder 23,5 KB:
Myke Black,
320

Verwenden von Log, um das Problem zu lösen ....

static String BytesToString(long byteCount)
{
    string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; //Longs run out around EB
    if (byteCount == 0)
        return "0" + suf[0];
    long bytes = Math.Abs(byteCount);
    int place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
    double num = Math.Round(bytes / Math.Pow(1024, place), 1);
    return (Math.Sign(byteCount) * num).ToString() + suf[place];
}

Auch in c #, sollte aber ein Kinderspiel sein. Außerdem habe ich zur besseren Lesbarkeit auf 1 Dezimalstelle gerundet.

Bestimmen Sie grundsätzlich die Anzahl der Dezimalstellen in Base 1024 und dividieren Sie diese durch 1024 ^ Dezimalstellen.

Und einige Verwendungs- und Ausgabebeispiele:

Console.WriteLine(BytesToString(9223372036854775807));  //Results in 8EB
Console.WriteLine(BytesToString(0));                    //Results in 0B
Console.WriteLine(BytesToString(1024));                 //Results in 1KB
Console.WriteLine(BytesToString(2000000));              //Results in 1.9MB
Console.WriteLine(BytesToString(-9023372036854775807)); //Results in -7.8EB

Bearbeiten: Es wurde darauf hingewiesen, dass ich einen math.floor verpasst habe, also habe ich ihn eingebaut. (Convert.ToInt32 verwendet Rundung, nicht Abschneiden, und deshalb ist Floor erforderlich.) Vielen Dank für den Haken.

Edit2: Es gab einige Kommentare zu negativen Größen und 0-Byte-Größen, daher habe ich aktualisiert, um diese beiden Fälle zu behandeln.

deepee1
quelle
7
Ich möchte warnen, dass diese Antwort zwar ein kurzer Code ist, aber nicht die am besten optimierte. Ich möchte, dass Sie sich die von @humbads veröffentlichte Methode ansehen. Ich habe Mikrotests durchgeführt und 10 000 000 zufällig generierte Dateigrößen mit beiden Methoden gesendet. Dies führt zu Zahlen, dass seine Methode ~ 30% schneller ist. Ich habe seine Methode jedoch weiter gereinigt (unnötige Aufgaben und Casting). Außerdem habe ich einen Test mit einer negativen Größe durchgeführt (wenn Sie Dateien vergleichen), während die Methode von Humbads dies fehlerfrei verarbeitet. Diese Log-Methode löst eine Ausnahme aus!
IvanL
1
Ja, Sie sollten Math.Abs ​​für negative Größen hinzufügen. Außerdem behandelt der Code den Fall nicht, wenn die Größe genau 0 ist.
Strichpunkt
Math.Abs, Math.Floor, Math.Log, Konvertieren in Ganzzahl, Math.Round, Math.Pow, Math.Sign, Hinzufügen, Multiplizieren, Dividieren? War das nicht eine Menge Mathe, die den Prozessor stark in Mitleidenschaft gezogen hat? Dies ist wahrscheinlich langsamer als @ Humbads Code
Jayson Ragasa
Fehlgeschlagen für double.MaxValue(Platz = 102)
BrunoLM
Funktioniert super! Ersetzen Sie die Math.Round durch Math.Ceiling, um die Funktionsweise von Windows nachzuahmen (zumindest unter Windows 7 Ultimate). Danke noch einmal. Ich mag diese Lösung.
H_He
101

Eine getestete und deutlich optimierte Version der angeforderten Funktion finden Sie hier:

C # Human Readable File Size - Optimierte Funktion

Quellcode:

// Returns the human-readable file size for an arbitrary, 64-bit file size 
// The default format is "0.### XB", e.g. "4.2 KB" or "1.434 GB"
public string GetBytesReadable(long i)
{
    // Get absolute value
    long absolute_i = (i < 0 ? -i : i);
    // Determine the suffix and readable value
    string suffix;
    double readable;
    if (absolute_i >= 0x1000000000000000) // Exabyte
    {
        suffix = "EB";
        readable = (i >> 50);
    }
    else if (absolute_i >= 0x4000000000000) // Petabyte
    {
        suffix = "PB";
        readable = (i >> 40);
    }
    else if (absolute_i >= 0x10000000000) // Terabyte
    {
        suffix = "TB";
        readable = (i >> 30);
    }
    else if (absolute_i >= 0x40000000) // Gigabyte
    {
        suffix = "GB";
        readable = (i >> 20);
    }
    else if (absolute_i >= 0x100000) // Megabyte
    {
        suffix = "MB";
        readable = (i >> 10);
    }
    else if (absolute_i >= 0x400) // Kilobyte
    {
        suffix = "KB";
        readable = i;
    }
    else
    {
        return i.ToString("0 B"); // Byte
    }
    // Divide by 1024 to get fractional value
    readable = (readable / 1024);
    // Return formatted number with suffix
    return readable.ToString("0.### ") + suffix;
}
Humbads
quelle
1
+1! Einfacher und unkomplizierter! Lässt den Prozessor einfach und schneller rechnen!
Jayson Ragasa
Zu Ihrer Information, Sie verwenden den Wert double readable = (i < 0 ? -i : i);nirgendwo, also entfernen Sie ihn. eine weitere Sache, die Besetzung ist redaundat
Royi Namir
Ich habe die Besetzung entfernt, Kommentare hinzugefügt und ein Problem mit dem negativen Vorzeichen behoben.
Humbads
Gute Antwort. Danke, warum nicht einfach benutzen Math.Abs?
Kspearrin
1
(i <0? -i: i) ist ungefähr 15% schneller als Math.Abs. Bei einer Million Anrufen ist Math.Abs ​​auf meinem Computer 0,5 Millisekunden langsamer - 3,2 ms gegenüber 3,7 ms.
Humbads
72
[DllImport ( "Shlwapi.dll", CharSet = CharSet.Auto )]
public static extern long StrFormatByteSize ( 
        long fileSize
        , [MarshalAs ( UnmanagedType.LPTStr )] StringBuilder buffer
        , int bufferSize );


/// <summary>
/// Converts a numeric value into a string that represents the number expressed as a size value in bytes, kilobytes, megabytes, or gigabytes, depending on the size.
/// </summary>
/// <param name="filelength">The numeric value to be converted.</param>
/// <returns>the converted string</returns>
public static string StrFormatByteSize (long filesize) {
     StringBuilder sb = new StringBuilder( 11 );
     StrFormatByteSize( filesize, sb, sb.Capacity );
     return sb.ToString();
}

Von: http://www.pinvoke.net/default.aspx/shlwapi/StrFormatByteSize.html

Bob
quelle
36
Ich mag ein Noob sein, aber es ist ein großer Missbrauch, solch gigantische Kanonen als Pinvoke zu verwenden, um diese Ente zu töten.
Bart
27
Verwendet der Explorer dies? Wenn ja, dann sehr nützlich, damit die Leute die Dateigröße, die Sie ihnen zeigen, mit dem übereinstimmen lassen, was der Explorer anzeigt.
Andrew Backer
8
Und eine, die das Rad nicht neu erfindet
Matthew Lock
Sind 11 Zeichen nicht eine konstante Grenze und dafür ein bisschen niedrig? Ich meine, andere Sprachen verwenden möglicherweise mehr Zeichen für das Akronym für die Bytegröße oder andere Formatierungsstile.
Ray
1
@Bart Es dauert eine Weile, bis Noobs die Weisheit darin erlernen: "Wir sollten kleine Effizienzvorteile vergessen, etwa 97% der Zeit: Vorzeitige Optimierung ist die Wurzel allen Übels" ubiquity.acm.org/article.cfm? id = 1513451
Matthew Lock
22

Eine weitere Möglichkeit, es zu häuten, ohne Schleifen und mit Unterstützung für negative Größen (sinnvoll für Dinge wie Deltas mit Dateigröße):

public static class Format
{
    static string[] sizeSuffixes = {
        "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };

    public static string ByteSize(long size)
    {
        Debug.Assert(sizeSuffixes.Length > 0);

        const string formatTemplate = "{0}{1:0.#} {2}";

        if (size == 0)
        {
            return string.Format(formatTemplate, null, 0, sizeSuffixes[0]);
        }

        var absSize = Math.Abs((double)size);
        var fpPower = Math.Log(absSize, 1000);
        var intPower = (int)fpPower;
        var iUnit = intPower >= sizeSuffixes.Length
            ? sizeSuffixes.Length - 1
            : intPower;
        var normSize = absSize / Math.Pow(1000, iUnit);

        return string.Format(
            formatTemplate,
            size < 0 ? "-" : null, normSize, sizeSuffixes[iUnit]);
    }
}

Und hier ist die Testsuite:

[TestFixture] public class ByteSize
{
    [TestCase(0, Result="0 B")]
    [TestCase(1, Result = "1 B")]
    [TestCase(1000, Result = "1 KB")]
    [TestCase(1500000, Result = "1.5 MB")]
    [TestCase(-1000, Result = "-1 KB")]
    [TestCase(int.MaxValue, Result = "2.1 GB")]
    [TestCase(int.MinValue, Result = "-2.1 GB")]
    [TestCase(long.MaxValue, Result = "9.2 EB")]
    [TestCase(long.MinValue, Result = "-9.2 EB")]
    public string Format_byte_size(long size)
    {
        return Format.ByteSize(size);
    }
}
Constantin
quelle
19

Überprüfen Sie die ByteSize- Bibliothek. Es ist das System.TimeSpanfür Bytes!

Es übernimmt die Konvertierung und Formatierung für Sie.

var maxFileSize = ByteSize.FromKiloBytes(10);
maxFileSize.Bytes;
maxFileSize.MegaBytes;
maxFileSize.GigaBytes;

Es werden auch Zeichenfolgen dargestellt und analysiert.

// ToString
ByteSize.FromKiloBytes(1024).ToString(); // 1 MB
ByteSize.FromGigabytes(.5).ToString();   // 512 MB
ByteSize.FromGigabytes(1024).ToString(); // 1 TB

// Parsing
ByteSize.Parse("5b");
ByteSize.Parse("1.55B");
Omar
quelle
5
Es ist deine eigene Bibliothek, nein?
Larsenal
10
Keine Schande in einer handlichen Bibliothek wie dieser. :-)
Larsenal
13

Ich verwende gerne die folgende Methode (sie unterstützt bis zu Terabyte, was für die meisten Fälle ausreicht, aber leicht erweitert werden kann):

private string GetSizeString(long length)
{
    long B = 0, KB = 1024, MB = KB * 1024, GB = MB * 1024, TB = GB * 1024;
    double size = length;
    string suffix = nameof(B);

    if (length >= TB) {
        size = Math.Round((double)length / TB, 2);
        suffix = nameof(TB);
    }
    else if (length >= GB) {
        size = Math.Round((double)length / GB, 2);
        suffix = nameof(GB);
    }
    else if (length >= MB) {
        size = Math.Round((double)length / MB, 2);
        suffix = nameof(MB);
    }
    else if (length >= KB) {
        size = Math.Round((double)length / KB, 2);
        suffix = nameof(KB);
    }

    return $"{size} {suffix}";
}

Bitte beachten Sie, dass dies für C # 6.0 (2015) geschrieben wurde, sodass für frühere Versionen möglicherweise eine kleine Bearbeitung erforderlich ist.

Kennzeichen
quelle
11
int size = new FileInfo( filePath ).Length / 1024;
string humanKBSize = string.Format( "{0} KB", size );
string humanMBSize = string.Format( "{0} MB", size / 1024 );
string humanGBSize = string.Format( "{0} GB", size / 1024 / 1024 );
TcKs
quelle
Gute Antwort. Es sollte ein Problem geben, wenn die Dateigröße zu klein ist. In diesem Fall gibt / 1024 0 zurück. Sie können einen gebrochenen Typ und einen Aufruf Math.Ceilingoder etwas anderes verwenden.
Nawfal
10

Hier ist eine kurze Antwort, die das Gerät automatisch bestimmt.

public static string ToBytesCount(this long bytes)
{
    int unit = 1024;
    string unitStr = "b";
    if (bytes < unit) return string.Format("{0} {1}", bytes, unitStr);
    else unitStr = unitStr.ToUpper();
    int exp = (int)(Math.Log(bytes) / Math.Log(unit));
    return string.Format("{0:##.##} {1}{2}", bytes / Math.Pow(unit, exp), "KMGTPEZY"[exp - 1], unitStr);
}

"b" steht für Bit, "B" steht für Byte und "KMGTPEZY" steht für Kilo, Mega, Giga, Tera, Peta, Exa, Zetta und Yotta

Man kann es erweitern, um ISO / IEC80000 zu berücksichtigen:

public static string ToBytesCount(this long bytes, bool isISO = true)
{
    int unit = 1024;
    string unitStr = "b";
    if (!isISO) unit = 1000;
    if (bytes < unit) return string.Format("{0} {1}", bytes, unitStr);
    else unitStr = unitStr.ToUpper();
    if (isISO) unitStr = "i" + unitStr;
    int exp = (int)(Math.Log(bytes) / Math.Log(unit));
    return string.Format("{0:##.##} {1}{2}", bytes / Math.Pow(unit, exp), "KMGTPEZY"[exp - 1], unitStr);
}
DKH
quelle
1
für alle, die sich fragen, warum es ein oAfter-KMGTPE gibt: Sein Französisch ( byteist octetauf Französisch). Für jede andere Sprache ersetzen Sie einfach odieb
Max R.
7
string[] suffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
int s = 0;
long size = fileInfo.Length;

while (size >= 1024)
{
    s++;
    size /= 1024;
}

string humanReadable = String.Format("{0} {1}", size, suffixes[s]);
bobwienholt
quelle
Sie sollten Folgendes überprüfen: while (Größe> = 1024 && s <Suffixe.Length).
TcKs
nein ... eine 64-Bit-Ganzzahl mit Vorzeichen kann nicht über die ZB hinausgehen ... die die Zahlen 2 ^ 70 darstellt.
Bobwienholt
7
Warum also YB eingeben?
Konfigurator
Ich mag diese Antwort am liebsten selbst, aber jeder hier hat wirklich ineffiziente Lösungen eingeführt. Sie sollten "Größe = Größe >> 10" verwenden. Die Verschiebung ist so viel schneller als die Division ... und ich denke, dass es gut ist, die zu haben Es gibt zusätzliche griechische Spezifizierer, da eine bewegliche DLR-Funktion in naher Zukunft nicht die "lange Größe" benötigen würde. Sie könnten sich auf einer 128-Bit-Vektor-CPU oder etwas befinden, das ZB und größer halten kann;)
RandomNickName42
4
Bitshifting war in den Tagen der C-Codierung auf dem Metall effizienter als die Division. Haben Sie einen Perf-Test in .NET durchgeführt, um festzustellen, ob die Bitverschiebung wirklich effizienter ist? Vor nicht allzu langer Zeit habe ich mir den Status des XOR-Swaps angesehen und festgestellt, dass er in .NET tatsächlich langsamer ist als bei Verwendung einer temporären Variablen.
Pete
7

Wenn Sie versuchen, die in der Detailansicht von Windows Explorer angezeigte Größe anzupassen, ist dies der gewünschte Code:

[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
private static extern long StrFormatKBSize(
    long qdw,
    [MarshalAs(UnmanagedType.LPTStr)] StringBuilder pszBuf,
    int cchBuf);

public static string BytesToString(long byteCount)
{
    var sb = new StringBuilder(32);
    StrFormatKBSize(byteCount, sb, sb.Capacity);
    return sb.ToString();
}

Dies entspricht nicht nur genau dem Explorer, sondern liefert auch die für Sie übersetzten Zeichenfolgen und die Unterschiede in Windows-Versionen (z. B. in Win10, K = 1000 gegenüber früheren Versionen K = 1024).

Metalogic
quelle
Dieser Code wird nicht kompiliert. Sie müssen die DLL angeben, von der die Funktion stammt. Der Prototyp der gesamten Funktion klingt also folgendermaßen: [DllImport ("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern long StrFormatKBSize (long qdw, [MarshalAs (UnmanagedType.LPTStr)] StringBuilder pszBuf, int cchBuf ); Lassen Sie mich der Erste sein, der diese Lösung befürwortet. Warum das Rad neu erfinden, wenn das Rad bereits erfunden wurde? Dies ist ein typischer Ansatz aller C # -Programmierer, aber leider erreicht C # nicht alle Ziele, die C ++ erreicht.
TarmoPikaro
Und noch ein Bugfix: Int64.MaxValue erreicht 9.223.372.036.854.775.807, was die Zuweisung einer Puffergröße von 25+ erfordert - ich habe es für alle Fälle auf 32 gerundet (nicht 11 wie im obigen Demo-Code).
TarmoPikaro
Danke @TarmoPikaro. Beim Kopieren aus meinem Arbeitscode habe ich den DllImport verpasst. Erhöhen Sie auch die Puffergröße gemäß Ihrer Empfehlung. Guter Fang!
Metalogic
beeindruckender Ansatz
tbhaxor
Dies zeigt nur die KB-Einheit. Die Idee ist, die größte Einheit je nach Wert anzuzeigen.
jstuardo
5

Mischung aller Lösungen :-)

    /// <summary>
    /// Converts a numeric value into a string that represents the number expressed as a size value in bytes,
    /// kilobytes, megabytes, or gigabytes, depending on the size.
    /// </summary>
    /// <param name="fileSize">The numeric value to be converted.</param>
    /// <returns>The converted string.</returns>
    public static string FormatByteSize(double fileSize)
    {
        FileSizeUnit unit = FileSizeUnit.B;
        while (fileSize >= 1024 && unit < FileSizeUnit.YB)
        {
            fileSize = fileSize / 1024;
            unit++;
        }
        return string.Format("{0:0.##} {1}", fileSize, unit);
    }

    /// <summary>
    /// Converts a numeric value into a string that represents the number expressed as a size value in bytes,
    /// kilobytes, megabytes, or gigabytes, depending on the size.
    /// </summary>
    /// <param name="fileInfo"></param>
    /// <returns>The converted string.</returns>
    public static string FormatByteSize(FileInfo fileInfo)
    {
        return FormatByteSize(fileInfo.Length);
    }
}

public enum FileSizeUnit : byte
{
    B,
    KB,
    MB,
    GB,
    TB,
    PB,
    EB,
    ZB,
    YB
}
NET3
quelle
4

Es gibt ein Open Source-Projekt, das das und noch viel mehr kann.

7.Bits().ToString();         // 7 b
8.Bits().ToString();         // 1 B
(.5).Kilobytes().Humanize();   // 512 B
(1000).Kilobytes().ToString(); // 1000 KB
(1024).Kilobytes().Humanize(); // 1 MB
(.5).Gigabytes().Humanize();   // 512 MB
(1024).Gigabytes().ToString(); // 1 TB

http://humanizr.net/#bytesize

https://github.com/MehdiK/Humanizer

Jernej Novak
quelle
3

Wie die Lösung von @ NET3. Verwenden Sie Shift anstelle von Division, um den Bereich von zu testen bytes, da Division mehr CPU-Kosten verursacht.

private static readonly string[] UNITS = new string[] { "B", "KB", "MB", "GB", "TB", "PB", "EB" };

public static string FormatSize(ulong bytes)
{
    int c = 0;
    for (c = 0; c < UNITS.Length; c++)
    {
        ulong m = (ulong)1 << ((c + 1) * 10);
        if (bytes < m)
            break;
    }

    double n = bytes / (double)((ulong)1 << (c * 10));
    return string.Format("{0:0.##} {1}", n, UNITS[c]);
}
user1448446
quelle
2

Ich nehme an, Sie suchen nach "1,4 MB" anstelle von "1468006 Bytes"?

Ich glaube nicht, dass es in .NET eine integrierte Möglichkeit gibt, dies zu tun. Sie müssen nur herausfinden, welches Gerät geeignet ist, und es formatieren.

Bearbeiten: Hier ist ein Beispielcode, um genau das zu tun:

http://www.codeproject.com/KB/cpp/formatsize.aspx

Peter Crabtree
quelle
2

Wie wäre es mit einer Rekursion:

private static string ReturnSize(double size, string sizeLabel)
{
  if (size > 1024)
  {
    if (sizeLabel.Length == 0)
      return ReturnSize(size / 1024, "KB");
    else if (sizeLabel == "KB")
      return ReturnSize(size / 1024, "MB");
    else if (sizeLabel == "MB")
      return ReturnSize(size / 1024, "GB");
    else if (sizeLabel == "GB")
      return ReturnSize(size / 1024, "TB");
    else
      return ReturnSize(size / 1024, "PB");
  }
  else
  {
    if (sizeLabel.Length > 0)
      return string.Concat(size.ToString("0.00"), sizeLabel);
    else
      return string.Concat(size.ToString("0.00"), "Bytes");
  }
}

Dann nennst du es:

return ReturnSize(size, string.Empty);
RooiWillie
quelle
Gut, aber es frisst CPU
Kamalpreet
1

Meine 2 Cent:

  • Das Präfix für Kilobyte ist kB (Kleinbuchstabe K)
  • Da diese Funktionen zu Präsentationszwecken dienen, sollte eine Kultur bereitgestellt werden, zum Beispiel: string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
  • Je nach Kontext kann ein Kilobyte entweder 1000 oder 1024 Byte betragen . Gleiches gilt für MB, GB usw.
Berend
quelle
3
Ein Kilobyte bedeutet 1000 Bytes ( wolframalpha.com/input/?i=kilobyte ), es hängt nicht vom Kontext ab. Es hing historisch vom Kontext ab, wie Wikipedia sagt, und es wurde de jure 1998 geändert und de facto begann die Änderung um 2005, als Terabyte-Festplatten es der Öffentlichkeit bekannt machten. Der Begriff für 1024 Bytes ist Kibibyte. Code, der sie basierend auf der Kultur wechselt, erzeugt falsche Informationen.
Superbest
1

Noch ein Ansatz für das, was es wert ist. Ich mochte die oben erwähnte optimierte @ humbads-Lösung, habe also das Prinzip kopiert, aber ich habe es etwas anders implementiert.

Ich nehme an, es ist fraglich, ob es eine Erweiterungsmethode sein sollte (da nicht alle Longs notwendigerweise Byte-Größen haben), aber ich mag sie und es ist irgendwo, wo ich die Methode finden kann, wenn ich sie das nächste Mal brauche!

In Bezug auf die Einheiten glaube ich nicht, dass ich jemals in meinem Leben "Kibibyte" oder "Mebibyte" gesagt habe, und obwohl ich skeptisch gegenüber solchen erzwungenen und nicht weiterentwickelten Standards bin, denke ich, dass dies langfristig Verwirrung vermeiden wird .

public static class LongExtensions
{
    private static readonly long[] numberOfBytesInUnit;
    private static readonly Func<long, string>[] bytesToUnitConverters;

    static LongExtensions()
    {
        numberOfBytesInUnit = new long[6]    
        {
            1L << 10,    // Bytes in a Kibibyte
            1L << 20,    // Bytes in a Mebibyte
            1L << 30,    // Bytes in a Gibibyte
            1L << 40,    // Bytes in a Tebibyte
            1L << 50,    // Bytes in a Pebibyte
            1L << 60     // Bytes in a Exbibyte
        };

        // Shift the long (integer) down to 1024 times its number of units, convert to a double (real number), 
        // then divide to get the final number of units (units will be in the range 1 to 1023.999)
        Func<long, int, string> FormatAsProportionOfUnit = (bytes, shift) => (((double)(bytes >> shift)) / 1024).ToString("0.###");

        bytesToUnitConverters = new Func<long,string>[7]
        {
            bytes => bytes.ToString() + " B",
            bytes => FormatAsProportionOfUnit(bytes, 0) + " KiB",
            bytes => FormatAsProportionOfUnit(bytes, 10) + " MiB",
            bytes => FormatAsProportionOfUnit(bytes, 20) + " GiB",
            bytes => FormatAsProportionOfUnit(bytes, 30) + " TiB",
            bytes => FormatAsProportionOfUnit(bytes, 40) + " PiB",
            bytes => FormatAsProportionOfUnit(bytes, 50) + " EiB",
        };
    }

    public static string ToReadableByteSizeString(this long bytes)
    {
        if (bytes < 0)
            return "-" + Math.Abs(bytes).ToReadableByteSizeString();

        int counter = 0;
        while (counter < numberOfBytesInUnit.Length)
        {
            if (bytes < numberOfBytesInUnit[counter])
                return bytesToUnitConverters[counter](bytes);
            counter++;
        }
        return bytesToUnitConverters[counter](bytes);
    }
}
Giles
quelle
0

Ich verwende die Long- Erweiterungsmethode unten, um sie in eine von Menschen lesbare Größenzeichenfolge zu konvertieren. Diese Methode ist die C # -Implementierung der Java-Lösung derselben Frage, die hier im Stapelüberlauf veröffentlicht wurde .

/// <summary>
/// Convert a byte count into a human readable size string.
/// </summary>
/// <param name="bytes">The byte count.</param>
/// <param name="si">Whether or not to use SI units.</param>
/// <returns>A human readable size string.</returns>
public static string ToHumanReadableByteCount(
    this long bytes
    , bool si
)
{
    var unit = si
        ? 1000
        : 1024;

    if (bytes < unit)
    {
        return $"{bytes} B";
    }

    var exp = (int) (Math.Log(bytes) / Math.Log(unit));

    return $"{bytes / Math.Pow(unit, exp):F2} " +
           $"{(si ? "kMGTPE" : "KMGTPE")[exp - 1] + (si ? string.Empty : "i")}B";
}
Masterwok
quelle