【问题标题】:How do I get a human-readable file size in bytes abbreviation using .NET?如何使用 .NET 以字节缩写形式获得人类可读的文件大小?
【发布时间】:2010-09-21 20:26:12
【问题描述】:

如何使用 .NET 以字节缩写形式获得人类可读的文件大小?

示例: 输入 7,326,629 并显示 6.98 MB

【问题讨论】:

标签: c# .net vb.net filesize human-readable


【解决方案1】:

这可能不是最有效或最优化的方法,但如果您不熟悉对数数学,它会更容易阅读,并且对于大多数情况应该足够快。

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

【讨论】:

  • 这正是我会做的...除了我会使用“{0:0.#}{1}”作为格式字符串...通常不需要两位数在点之后,我不喜欢在那里放一个空格。但这只是我。
  • 我相信您可以使用 Math.Log 来确定顺序,而不是使用 while 循环。
  • @Constantin 好吧,这取决于操作系统? Windows 仍然将 1024 字节计为 1 KB 和 1 MB = 1024 KB,就我个人而言,我想将 KiB 扔出窗外,只使用 1024 来计算每一件事?...
  • @Petoj 它不依赖于操作系统,定义与操作系统无关。来自维基百科:The unit was established by the International Electrotechnical Commission (IEC) in 1998 and has been accepted for use by all major standards organizations
  • 我更喜欢这个代码,因为它似乎运行得更快,但我稍微修改了它以允许不同的小数位数。较小的数字最好显示 2 位小数,例如 1.38MB,而较大的数字需要较少的小数,例如 246k 或 23.5KB:
【解决方案2】:

使用Log解决问题....

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

也在 C# 中,但应该很容易转换。为了便于阅读,我还四舍五入到小数点后 1 位。

基本确定Base 1024的小数位数,然后除以1024^decimalplaces

以及一些使用和输出示例:

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

编辑:
有人指出我错过了Math.Floor,所以我合并了它。 (Convert.ToInt32 使用舍入,而不是截断,这就是为什么需要Floor。)感谢您的关注。

编辑2:
有几个关于负大小和 0 字节大小的 cmets,所以我更新以处理这些情况。

【讨论】:

  • 我想警告说,虽然这个答案确实是一小段代码,但它并不是最优化的。我想让你看看@humbads 发布的方法。我进行了微测试,通过这两种方法发送了 10 000 000 个随机生成的文件大小,这表明他的方法快了约 30%。然而,我对他的方法做了一些进一步的清理(不必要的任务和铸造)。此外,我运行了一个负大小的测试(当您比较文件时),而 humbads 的方法完美地处理了这个 Log 方法将抛出异常!
  • 是的,您应该为负尺寸添加 Math.Abs​​。此外,如果大小正好为 0,则代码不会处理这种情况。
  • Math.Abs​​、Math.Floor、Math.Log、转换为整数、Math.Round、Math.Pow、Math.Sign、加法、乘法、除法?这么多的数学运算不是对处理器造成了巨大的影响吗?这可能比@humbads 代码慢
  • double.MaxValue 失败(位置 = 102)
  • 效果很好!要模仿 Windows 的工作方式(至少在我的 Windows 7 终极版上),请将 Math.Round 替换为 Math.Ceiling。再次感谢。我喜欢这个解决方案。
【解决方案3】:

此处发布了经过测试且经过显着优化的请求功能版本:

C# Human Readable File Size - Optimized Function

源代码:

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

【讨论】:

  • +1!更简单直接!让处理器更轻松、更快速地进行数学运算!
  • 仅供参考,您不会在任何地方使用 double readable = (i &lt; 0 ? -i : i); 中的值,因此请将其删除。还有一件事,演员阵容是多余的
  • 我删除了演员表,添加了 cmets,并修复了负号问题。
  • (i
  • 应该是“MiB”、“KiB”等?
【解决方案4】:
[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();
}

发件人:http://www.pinvoke.net/default.aspx/shlwapi/StrFormatByteSize.html

【讨论】:

  • 我可能是个菜鸟,但是使用像pinvoke这样的巨型大炮来杀死那只鸭子是一个很大的误用。
  • 这是 explorer 使用的吗?如果是这样,那么对于让人们将您显示给他们的文件大小与资源管理器显示的内容进行匹配非常有用。
  • 而且不会重新发明轮子
  • @Matthew 我知道这句话,它是我的最爱之一。但我评论的重点不是解决效率而是纯度。在 PInvoke 上进行中继是我们安全管理世界中的最后也是终极武器。当我们为这项任务完美管理代码时,为什么我们要带来任何风险,即有一天这个外部函数会失败或被删除?我们应该依赖于此测试我们的代码吗?它会在Linux上工作吗?等等等等。这么多额外的问题,我认为投票得分最高的答案没有潜在的好处。
  • 这绝对是不是的方法。如果您想完全匹配操作系统显示的大小,它可能在非常特定的情况下对仅限 Windows 的程序有用;但是,在 Windows 10 中,该函数使用基数 10 而不是基数 2(1 KB = 1000 字节而不是 1024),因此相同的代码会根据运行的 Windows 版本产生不同的输出。最后,如果您正在编写跨平台代码,这完全没用。
【解决方案5】:

查看ByteSize 库。这是 System.TimeSpan 字节!

它为您处理转换和格式化。

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

它还进行字符串表示和解析。

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

【讨论】:

  • 这是你自己的图书馆,不是吗?
  • 在这样一个方便的库中并不感到羞耻。 :-)
【解决方案6】:

另一种皮肤的方法,没有任何类型的循环和负大小支持(对于文件大小增量等有意义):

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

这里是测试套件:

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

【讨论】:

    【解决方案7】:

    我喜欢使用下面的方法(它支持高达TB,这对于大多数情况来说已经足够了,但它可以很容易地扩展):

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

    请记住,这是为 C# 6.0 (2015) 编写的,因此可能需要对早期版本进行一些编辑。

    【讨论】:

      【解决方案8】:
      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 );
      

      【讨论】:

      • 好答案。文件大小太小应该有问题,这种情况下/1024返回0。你可以使用小数类型并调用Math.Ceiling之类的。
      【解决方案9】:

      这是一个自动确定单位的简明答案。

      public static string ToBytesCount(this long bytes)
      {
          int unit = 1024;
          string unitStr = "B";
          if (bytes < unit)
          {
              return string.Format("{0} {1}", bytes, 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);
      }
      

      “b”代表比特,“B”代表字节,“KMGTPEZY”分别代表千、兆、千兆、兆、兆、埃、泽塔和约塔

      可以将其扩展为将ISO/IEC80000 考虑在内:

      public static string ToBytesCount(this long bytes, bool isISO = true)
      {
          int unit = isISO ? 1024 : 1000;
          string unitStr = "B";
          if (bytes < unit)
          {
              return string.Format("{0} {1}", bytes, unitStr);
          }
          int exp = (int)(Math.Log(bytes) / Math.Log(unit));
          return string.Format("{0:##.##} {1}{2}{3}", bytes / Math.Pow(unit, exp), "KMGTPEZY"[exp - 1], isISO ? "i" : "", unitStr);
      }
      

      【讨论】:

      • 每个人都想知道为什么在 KMGTPE 之后有一个o:它的法语(byte 在法语中是 octet)。对于任何其他语言,只需将 o 替换为 b
      • 方法引用字节;如前所述,使用 "B' 是正确的情况,而不是 "b" 用于unitStr ;)
      • 谢谢@shA.t,不记得我为什么这么改了...(见en.wikipedia.org/wiki/Byte)。
      【解决方案10】:
      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]);
      

      【讨论】:

      • 你应该检查一下:while(size >= 1024 && s
      • nope... 64 位有符号整数不能超出 ZB... 代表数字 2^70。
      • 我自己最喜欢这个答案,但是这里的每个人都提出了非常低效的解决方案,你应该使用“size = size >> 10”移位比除法快得多......而且我认为在那里有额外的希腊语说明符很好,因为在不久的将来,一个可行的 DLR 函数不需要“长尺寸..”你可以在 128 位向量 cpu 或可以容纳 ZB 和更大的东西上; )
      • 在金属上使用 C 编码的时代,位移比除法更有效。您是否在 .NET 中进行过性能测试以查看 bitshift 是否真的更有效?不久前,我查看了 xor-swap 的状态,发现它在 .NET 中实际上比使用临时变量要慢。
      【解决方案11】:

      如果您尝试匹配 Windows 资源管理器的详细视图中显示的大小,这就是您想要的代码:

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

      这不仅会完全匹配 Explorer,还会提供为您翻译的字符串并匹配 Windows 版本中的差异(例如在 Win10 中,K = 1000 与以前的版本 K = 1024)。

      【讨论】:

      • 这段代码无法编译,需要指定函数来自哪个dll。所以整个函数原型听起来像这样: [DllImport("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern long StrFormatKBSize(long qdw, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder pszBuf, int cchBuf );让我成为第一个支持这个解决方案的人。如果已经发明了轮子,为什么要重新发明轮子?这是所有 C# 程序员的典型做法,但不幸的是 C# 并没有达到 C++ 达到的所有目标。
      • 还有一个错误修复:Int64.MaxValue 达到 9,223,372,036,854,775,807,这需要分配 25+ 的缓冲区大小 - 我已将其四舍五入为 32 以防万一(而不是像上面的演示代码中的 11)。
      • 谢谢@TarmoPikaro。当我从我的工作代码中复制时,我错过了 DllImport。还根据您的建议增加了缓冲区大小。好收获!
      • 令人印象深刻的方法
      • 这仅显示 KB 单位。这个想法是根据值显示最大的单位。
      【解决方案12】:

      有一个开源项目可以做到这一点,甚至更多。

      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

      【讨论】:

        【解决方案13】:

        所有解决方案的混合 :-)

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

        【讨论】:

          【解决方案14】:

          喜欢@NET3 的解决方案。使用 shift 代替除法来测试bytes 的范围,因为除法需要更多的 CPU 开销。

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

          【讨论】:

            【解决方案15】:

            我使用下面的 Long 扩展方法来转换为人类可读大小的字符串。此方法是 Stack Overflow 上发布的同一问题的 Java 解决方案的 C# 实现,here

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

            【讨论】:

              【解决方案16】:

              我假设您正在寻找“1.4 MB”而不是“1468006 字节”?

              我认为 .NET 中没有内置的方法可以做到这一点。你只需要弄清楚哪个单位是合适的,然后格式化。

              编辑:这里有一些示例代码可以做到这一点:

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

              【讨论】:

                【解决方案17】:

                一些递归怎么样:

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

                那你叫它:

                return ReturnSize(size, string.Empty);
                

                【讨论】:

                • 不错,但它会吃掉 CPU
                【解决方案18】:

                为了获得完全符合用户在其 Windows 环境中习惯的可读字符串,您应该使用StrFormatByteSize()

                using System.Runtime.InteropServices;
                

                ...

                private long mFileSize;
                
                [DllImport("Shlwapi.dll", CharSet = CharSet.Auto)]
                public static extern int StrFormatByteSize(
                    long fileSize,
                    [MarshalAs(UnmanagedType.LPTStr)] StringBuilder buffer,
                    int bufferSize);
                    
                public string HumanReadableFileSize
                {
                    get
                    {
                        var sb = new StringBuilder(20);
                        StrFormatByteSize(mFileSize, sb, 20);
                        return sb.ToString();
                    }
                }
                

                我在这里找到了这个: http://csharphelper.com/blog/2014/07/format-file-sizes-in-kb-mb-gb-and-so-forth-in-c/

                【讨论】:

                  【解决方案19】:

                  我的 2 美分:

                  • 千字节的前缀是 kB(小写 K)
                  • 由于这些函数用于演示目的,因此应该提供一种文化,例如:string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
                  • 根据上下文,千字节可以是1000 or 1024 bytes。 MB、GB 等也是如此。

                  【讨论】:

                  • 一千字节表示 1000 字节 (wolframalpha.com/input/?i=kilobyte),它不依赖于上下文。正如维基百科所说,它从历史上看取决于上下文,它在 1998 年在法律上发生了变化,而事实上的变化始于 2005 年左右,当时 TB 级硬盘驱动器引起了公众的关注。 1024 字节的术语是千字节。根据文化切换它们的代码会产生不正确的信息。
                  • @Superbest 告诉 Windows。如果您在 Windows 上下文中,KB 为 1024,因此它确实取决于上下文。
                  【解决方案20】:

                  另一种方法,物有所值。我喜欢上面提到的@humbads 优化解决方案,所以复制了原理,但我的实现方式略有不同。

                  我想它是否应该是一个扩展方法是有争议的(因为不是所有的 long 都必须是字节大小),但我喜欢它们,而且当我下次需要它时,我可以在某个地方找到它!

                  关于单位,我认为我一生中从未说过“千字节”或“兆字节”,虽然我对这种强制执行而不是演变的标准持怀疑态度,但我想它会避免混淆长期的。

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

                  【讨论】:

                    【解决方案21】:

                    这是一个带有Log10的方法:

                    using System;
                    
                    class Program {
                       static string NumberFormat(double n) {
                          var n2 = (int)Math.Log10(n) / 3;
                          var n3 = n / Math.Pow(1e3, n2);
                          return String.Format("{0:f3}", n3) + new[]{"", " k", " M", " G"}[n2];
                       }
                    
                       static void Main() {
                          var s = NumberFormat(9012345678);
                          Console.WriteLine(s == "9.012 G");
                       }
                    }
                    

                    https://docs.microsoft.com/dotnet/api/system.math.log10

                    【讨论】:

                      【解决方案22】:

                      这是@deepee1's answerBigInteger 版本,它绕过了longs 的大小限制(因此支持yottabyte,理论上支持之后的任何内容):

                      public static string ToBytesString(this BigInteger byteCount, string format = "N3")
                      {
                          string[] suf = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "YiB" };
                          if (byteCount.IsZero)
                          {
                              return $"{0.0.ToString(format)} {suf[0]}";
                          }
                      
                          var abs = BigInteger.Abs(byteCount);
                          var place = Convert.ToInt32(Math.Floor(BigInteger.Log(abs, 1024)));
                          var pow = Math.Pow(1024, place);
                      
                          // since we need to do this with integer math, get the quotient and remainder
                          var quotient = BigInteger.DivRem(abs, new BigInteger(pow), out var remainder);
                          // convert the remainder to a ratio and add both back together as doubles
                          var num = byteCount.Sign * (Math.Floor((double)quotient) + ((double)remainder / pow));
                      
                          return $"{num.ToString(format)} {suf[place]}";
                      }
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2017-08-09
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-02-06
                        • 2013-02-17
                        • 1970-01-01
                        相关资源
                        最近更新 更多