如何使用.NET获得以字节为单位的人类可读文件大小?

Lar*_*nal 265 .net c# vb.net

如何使用.NET获得以字节为单位的人类可读文件大小?

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

Dav*_*ult 339

这不是最有效的方法,但如果您不熟悉日志数学,则更容易阅读,并且对于大多数情况应该足够快.

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]);
Run Code Online (Sandbox Code Playgroud)

  • 我相信您可以使用Math.Log来确定顺序而不是使用while循环. (12认同)
  • @Constantin那取决于操作系统?Windows仍然计算1024字节为1 KB和1 MB = 1024 KB,我个人想把KiB抛出窗口,只计算使用1024的所有东西?... (12认同)
  • 此外,KB是1000字节.1024字节是[KiB](http://en.wikipedia.org/wiki/Kibibyte). (10认同)
  • @Petoj它不依赖于操作系统,其定义与操作系统无关。摘自Wikipedia:`该单元由国际电工委员会(IEC)于1998年建立,并已为所有主要标准组织所接受。 (3认同)
  • 我更喜欢这个代码,因为它似乎运行得更快但我稍微修改它以允许不同的小数位数.较小的数字更好地显示2位小数,例如1.38MB而较大的数字需要较少的小数位,例如246k或23.5KB: (3认同)

dee*_*ee1 310

使用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];
}
Run Code Online (Sandbox Code Playgroud)

同样在c#中,但应该是快速转换.为了便于阅读,我还舍入到小数点后1位.

基本上确定Base 1024中的小数位数,然后除以1024 ^十进制位数.

以及一些使用和输出的样本:

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
Run Code Online (Sandbox Code Playgroud)

编辑:有人指出我错过了math.floor,所以我把它合并了.(Convert.ToInt32使用舍入,而不是截断,这就是为什么需要Floor.)感谢抓住.

Edit2:有一些关于负大小和0字节大小的评论,所以我更新了处理这两种情况.

  • 我想提醒一下,虽然这个答案确实是一小段代码,但它并不是最优化的.我想请你看一下@humbads发布的方法.我运行microtesting通过这两种方法发送了10 000 000个随机生成的文件大小,这就提出了他的方法快了大约30%的数字.然而,我做了一些进一步清理他的方法(不必要的任务和演员).此外,我运行了一个负大小的测试(当你比较文件时),而humbads的方法完美地处理这个这个Log方法将抛出异常! (7认同)

hum*_*ads 96

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

C#人类可读文件大小 - 优化功能

源代码:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 应该是“MiB”、“KiB”等吗? (4认同)
  • +1!更简单直接!使处理器轻松快速地进行数学运算! (2认同)
  • (i &lt; 0 ? -i : i) 比 Math.Abs​​ 快大约 15%。对于一百万次调用,Math.Abs​​ 在我的机器上慢了 0.5 毫秒 — 3.2 毫秒 vs 3.7 毫秒。 (2认同)

Bob*_*Bob 71

[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();
}
Run Code Online (Sandbox Code Playgroud)

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

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

Con*_*tin 21

另一种皮肤修饰方法,没有任何循环和负尺寸支持(对文件大小增量等内容有意义):

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]);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是测试套件:

[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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Oma*_*mar 14

签出ByteSize库.这是System.TimeSpan字节!

它为您处理转换和格式.

var maxFileSize = ByteSize.FromKiloBytes(10);
maxFileSize.Bytes;
maxFileSize.MegaBytes;
maxFileSize.GigaBytes;
Run Code Online (Sandbox Code Playgroud)

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

// 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");
Run Code Online (Sandbox Code Playgroud)

  • 像这样的便利图书馆没有羞耻.:-) (9认同)
  • 这是你自己的图书馆,不是吗? (4认同)

Mar*_*ark 12

我喜欢使用以下方法(它支持多达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}";
}
Run Code Online (Sandbox Code Playgroud)

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


TcK*_*cKs 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 );
Run Code Online (Sandbox Code Playgroud)


Jer*_*vak 9

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

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
Run Code Online (Sandbox Code Playgroud)

http:// humanizr.net/#bytesize

https://github.com/MehdiK/Humanizer


bob*_*olt 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]);
Run Code Online (Sandbox Code Playgroud)

  • 那么为什么要放入YB? (7认同)
  • 在C编码金属的时代,Bitshifting比分割更有效.你是否在.NET中进行过perf测试,看看bitshift是否真的更有效?不久前,我查看了xor-swap的状态,发现它在.NET中实际上比使用temp变量慢. (4认同)

DKH*_*DKH 7

这是一个简洁的答案,可以自动确定单位。

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);
}
Run Code Online (Sandbox Code Playgroud)

“ b”表示位,“ B”表示字节,“ KMGTPEZY”分别表示公斤,兆,千兆,Tera,peta,exa,zetta和yotta

可以扩展它以考虑到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);
}
Run Code Online (Sandbox Code Playgroud)


Met*_*gic 6

如果您尝试匹配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();
}
Run Code Online (Sandbox Code Playgroud)

这不仅会完全匹配资源管理器,还会提供为您翻译的字符串,并匹配Windows版本中的差异(例如,在Win10中,K = 1000与先前版本K = 1024).


NET*_*ET3 5

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

    /// <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
}
Run Code Online (Sandbox Code Playgroud)


小智 5

就像@NET3的解决方案一样。使用移位而不是除法来测试 的范围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]);
}
Run Code Online (Sandbox Code Playgroud)