Bagaimana cara mendapatkan ukuran file yang dapat dibaca manusia dalam singkatan bytes menggunakan .NET?

Jawaban:

353

Ini bukan cara yang paling efisien untuk melakukannya, tetapi lebih mudah dibaca jika Anda tidak terbiasa dengan matematika log, dan harus cukup cepat untuk sebagian besar skenario.

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
sumber
12
Saya percaya Anda bisa menggunakan Math.Log untuk menentukan urutan alih-alih menggunakan loop sementara.
Francois Botha
12
Juga, KB adalah 1000 byte. 1024 byte adalah KiB .
Constantin
13
@Konstantin juga tergantung pada OS? Windows masih menghitung 1024 byte sebagai 1 KB dan 1 MB = 1024 KB, Secara pribadi saya ingin membuang KiB keluar jendela dan hanya menghitung setiap hal menggunakan 1024? ...
Peter
4
@ Petoj itu tidak tergantung pada OS, definisi adalah OS-agnostik. Dari 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
Saya lebih suka kode ini karena tampaknya berjalan lebih cepat tetapi saya memodifikasinya sedikit untuk memungkinkan jumlah tempat desimal yang berbeda. Angka yang lebih kecil lebih baik menunjukkan 2 tempat desimal, misalnya 1,38MB sedangkan angka yang lebih besar membutuhkan desimal yang lebih sedikit misalnya 246k atau 23,5KB:
Myke Black
321

menggunakan Log untuk menyelesaikan masalah ....

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

Juga di c #, tetapi harus menjadi snap untuk mengkonversi. Saya juga membulatkan ke 1 tempat desimal untuk dibaca.

Pada dasarnya Tentukan jumlah tempat desimal di Basis 1024 dan kemudian bagi dengan 1024 ^ tempat desimal.

Dan beberapa contoh penggunaan dan keluaran:

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

Sunting: Menunjukkan bahwa saya melewatkan lantai math.for, jadi saya memasukkannya. (Convert.ToInt32 menggunakan pembulatan, tidak memotong dan itu sebabnya Lantai diperlukan.) Terima kasih atas tangkapannya.

Sunting2: Ada beberapa komentar tentang ukuran negatif dan ukuran 0 byte, jadi saya memperbarui untuk menangani 2 kasus itu.

deepee1
sumber
7
Saya ingin memperingatkan bahwa sementara jawaban ini memang sepotong kode pendek itu bukan yang paling dioptimalkan. Saya ingin Anda melihat metode yang diposting oleh @Humbads. Saya menjalankan microtesting mengirimkan 10 000 000 file yang dihasilkan secara acak melalui kedua metode dan ini menampilkan angka bahwa metodenya ~ 30% lebih cepat. Saya melakukan pembersihan lebih lanjut dari metodenya (penugasan & casting yang tidak khas). Selanjutnya saya menjalankan tes dengan ukuran negatif (ketika Anda membandingkan file) sementara metode humbad dengan sempurna memproses ini, metode Log ini akan melempar pengecualian!
IvanL
1
Yap, Anda harus menambahkan Math.Abs ​​untuk ukuran negatif. Lebih jauh lagi, kode ini tidak menangani casing jika ukurannya tepat 0.
dasheddot
Math.Abs, Math.Floor, Math.Log, Konversi ke integer, Math.Round, Math.Pow, Math.Sign, Menambah, Mengalikan, Membagi? Bukankah ini banyak matematika hanya membuat lonjakan besar pada prosesor. Ini mungkin lebih lambat dari kode @humbads
Jayson Ragasa
Gagal untuk double.MaxValue(tempat = 102)
BrunoLM
Bagus sekali! Untuk meniru cara kerja windows (setidaknya pada ultimate Windows 7 saya), ganti Math.Round dengan Math.Ceiling. Terima kasih lagi. Saya suka solusi ini.
Dia_
101

Versi yang diuji dan dioptimalkan secara signifikan dari fungsi yang diminta diposting di sini:

C # Ukuran File yang Dapat Dibaca Manusia - Fungsi yang Dioptimalkan

Kode sumber:

// 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;
}
humbad
sumber
1
+1! Lebih sederhana dan lurus ke depan! Membuat prosesor melakukan perhitungan dengan mudah dan cepat!
Jayson Ragasa
FYI, Anda tidak menggunakan nilai di double readable = (i < 0 ? -i : i);mana pun jadi hapus saja. satu hal lagi, pemerannya adalah redaundat
Royi Namir
Saya menghapus para pemain, menambahkan komentar, dan memperbaiki masalah dengan tanda negatif.
humbads
Jawaban yang bagus Terima kasih, Kenapa tidak pakai saja Math.Abs?
kspearrin
1
(i <0? -i: i) sekitar 15% lebih cepat dari Math.Abs. Untuk satu juta panggilan, Math.Abs ​​lebih lambat 0,5 milidetik pada mesin saya - 3,2 ms vs 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();
}

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

Bob
sumber
36
Saya mungkin seorang noob, tetapi menggunakan meriam raksasa seperti pinvoke untuk membunuh bebek itu adalah penyalahgunaan besar.
Bart
27
Apakah ini yang digunakan penjelajah? Jika demikian, maka sangat berguna untuk membiarkan orang-orang cocok dengan ukuran file yang Anda perlihatkan kepada mereka dengan apa yang ditampilkan oleh penjelajah.
Andrew Backer
8
Dan yang tidak menemukan kembali roda
Matthew Lock
Bukankah 11 karakter batas konstan dan sedikit rendah untuk itu? Maksudku, bahasa lain mungkin menggunakan lebih banyak karakter untuk akronim ukuran byte, atau gaya pemformatan lainnya.
Ray
1
@Bart, perlu beberapa saat bagi noobs untuk mempelajari kebijaksanaan dalam hal ini: "Kita harus melupakan efisiensi kecil, katakanlah sekitar 97% dari waktu: optimasi prematur adalah akar dari semua kejahatan" ubiquity.acm.org/article.cfm? id = 1513451
Matthew Lock
22

Satu lagi cara untuk mengulitinya, tanpa loop apa pun dan dengan dukungan ukuran negatif (masuk akal untuk hal-hal seperti delta ukuran file):

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

Dan di sini adalah test suite:

[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);
    }
}
Konstantin
sumber
19

Periksa perpustakaan ByteSize . Ini System.TimeSpanuntuk byte!

Ini menangani konversi dan pemformatan untuk Anda.

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

Itu juga melakukan representasi string dan parsing.

// 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
sumber
5
Ini perpustakaan Anda sendiri, bukan?
Larsenal
10
Tidak perlu malu di perpustakaan yang berguna seperti ini. :-)
Larsenal
13

Saya suka menggunakan metode berikut (ini mendukung hingga terabyte, yang cukup untuk sebagian besar kasus, tetapi dapat dengan mudah diperpanjang):

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

Harap diingat bahwa ini ditulis untuk C # 6.0 (2015), jadi mungkin perlu sedikit pengeditan untuk versi sebelumnya.

Menandai
sumber
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 );
TcK
sumber
Jawaban yang bagus. Seharusnya ada masalah ketika ukuran file terlalu kecil, di mana / 1024 mengembalikan 0. Anda bisa menggunakan tipe fraksional dan panggilan Math.Ceilingatau sesuatu.
nawfal
10

Inilah jawaban singkat yang menentukan unit secara otomatis.

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" adalah untuk bit, "B" adalah untuk Byte dan "KMGTPEZY" masing-masing untuk kilo, mega, giga, tera, peta, exa, zetta dan yotta

Seseorang dapat mengembangkannya untuk memperhitungkan ISO / IEC80000 :

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
sumber
1
untuk semua orang bertanya-tanya mengapa ada osetelah KMGTPE: Its french ( byteadalah octetdi Perancis). Untuk bahasa lain hanya ganti odenganb
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
sumber
Anda harus memeriksa: while (size> = 1024 && s <suffixes.Length).
TcK
tidak ... integer bertanda 64-bit tidak dapat melampaui ZB ... yang mewakili angka 2 ^ 70.
bobwienholt
7
Jadi mengapa dimasukkan ke YB?
konfigurator
Saya suka jawaban ini sendiri, tetapi semua orang di sini memberikan solusi yang benar-benar tidak efisien, Anda harus menggunakan shift "size = size >> 10" jauh lebih cepat daripada pembagian ... dan saya pikir sebaiknya memiliki ekstra Yunani specifier ada di sana, karena dalam waktu dekat, fungsi DLR yang mungkin tidak akan memerlukan "ukuran panjang .." Anda bisa pada cpu vektor 128 bit atau sesuatu yang dapat menampung ZB dan lebih besar;)
RandomNickName42
4
Bitshifting lebih efisien daripada pembagian pada zaman C coding pada logam. Sudahkah Anda melakukan tes perf dalam .NET untuk melihat apakah bitshift benar-benar lebih efisien? Belum lama ini, saya melihat keadaan xor-swap dan menemukan itu sebenarnya lebih lambat di .NET vs menggunakan variabel temp.
Pete
7

Jika Anda mencoba mencocokkan ukuran seperti yang ditunjukkan pada tampilan detail Windows Explorer, ini adalah kode yang Anda inginkan:

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

Ini tidak hanya cocok dengan Explorer tetapi juga akan memberikan string yang diterjemahkan untuk Anda dan cocok dengan perbedaan dalam versi Windows (misalnya di Win10, K = 1000 vs versi sebelumnya K = 1024).

Metalogik
sumber
Kode ini tidak mengkompilasi, Anda perlu menentukan dll dari mana fungsi berasal. Jadi prototipe seluruh fungsi terdengar seperti ini: [DllImport ("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern panjang StrFormatKBSize (qdw panjang, [MarshalAs (UnmanagedType.LPTStr)] StringBuilder pszBuf, int cuf ); Biarkan saya menjadi yang pertama yang mendukung solusi ini. Mengapa harus menemukan kembali roda jika roda sudah ditemukan? Ini adalah pendekatan khas semua programmer C #, tetapi sayangnya C # tidak mencapai semua target yang dicapai C ++.
TarmoPikaro
Dan satu lagi perbaikan bug: Int64.MaxValue mencapai 9.223.372.036.854.775.807, yang mengharuskan untuk mengalokasikan ukuran buffer 25+ - Saya telah membulatkannya menjadi 32 untuk berjaga-jaga (tidak 11 seperti dalam kode demo di atas).
TarmoPikaro
Terima kasih @TarmoPikaro. Ketika saya menyalin dari kode kerja saya, saya melewatkan DllImport. Juga meningkatkan ukuran buffer sesuai rekomendasi Anda. Tangkapan yang bagus!
Metalogic
pendekatan yang mengesankan
tbhaxor
Ini hanya menunjukkan unit KB. Idenya adalah untuk menunjukkan unit terbesar tergantung pada nilainya.
jstuardo
5

Campuran semua solusi :-)

    /// <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
sumber
4

Ada satu proyek open source yang bisa melakukan itu dan banyak lagi.

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
sumber
3

Seperti solusi @ NET3. Gunakan shift alih-alih divisi untuk menguji kisaran bytes, karena pembagian membutuhkan biaya CPU lebih banyak.

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]);
}
pengguna1448446
sumber
2

Saya menganggap Anda sedang mencari "1,4 MB" bukannya "1468006 byte"?

Saya tidak berpikir ada cara built-in untuk melakukan itu di .NET. Anda harus mencari tahu unit mana yang sesuai, dan memformatnya.

Sunting: Berikut beberapa contoh kode untuk melakukan hal itu:

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

Peter Crabtree
sumber
2

Bagaimana dengan beberapa rekursi:

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

Maka Anda menyebutnya:

return ReturnSize(size, string.Empty);
RooiWillie
sumber
Bagus tapi makan CPU
kamalpreet
1

2 sen saya:

  • Awalan untuk kilobyte adalah kB (huruf kecil K)
  • Karena fungsi-fungsi ini untuk tujuan presentasi, seseorang harus menyediakan budaya, misalnya: string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
  • Bergantung pada konteksnya, satu kilobyte dapat berupa 1000 atau 1024 byte . Hal yang sama berlaku untuk MB, GB, dll.
Berend
sumber
3
Satu kilobyte berarti 1000 byte ( wolframalpha.com/input/?i=kilobyte ), itu tidak tergantung pada konteks. Secara historis tergantung pada konteks, seperti kata wikipedia, dan perubahan itu terjadi pada tahun 1998 dan perubahan de facto dimulai sekitar tahun 2005 ketika hard drive terabyte membawanya ke perhatian publik. Istilah untuk 1024 byte adalah kibibyte. Kode yang mengalihkan mereka berdasarkan budaya menghasilkan informasi yang salah.
Biasa
1

Satu lagi pendekatan, untuk apa nilainya. Saya menyukai solusi teroptimalkan @humbads yang dirujuk di atas, jadi telah menyalin prinsipnya, tetapi saya telah menerapkannya sedikit berbeda.

Saya kira itu masih bisa diperdebatkan, apakah itu harus menjadi metode ekstensi (karena tidak semua lama harus ukuran byte), tapi saya suka mereka, dan di suatu tempat saya dapat menemukan metode ketika saya membutuhkannya nanti!

Mengenai unit, saya tidak berpikir saya pernah mengatakan 'Kibibyte' atau 'Mebibyte' dalam hidup saya, dan sementara saya skeptis dengan standar yang ditegakkan daripada berkembang, saya kira itu akan menghindari kebingungan dalam jangka panjang .

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
sumber
0

Saya menggunakan metode ekstensi Panjang di bawah ini untuk mengonversi string ukuran yang dapat dibaca manusia. Metode ini adalah implementasi C # dari solusi Java untuk pertanyaan yang sama yang diposting di Stack Overflow, di sini .

/// <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
sumber