我如何获得一个人类可读的文件大小字节缩写使用。net ?

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


当前回答

我的观点是:

千字节的前缀是kB(小写K) 由于这些函数用于表示目的,因此应该提供区域性,例如:CurrentCulture,“{0时。##}{1}",文件大小,单位); 根据上下文,千字节可以是1000字节或1024字节。MB、GB等也是如此。

其他回答

如果你试图匹配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();
}

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

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

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

1-liner(加上前缀常量)

const String prefixes = " KMGTPEY";
/// <summary> Returns the human-readable file size for an arbitrary, 64-bit file size. </summary>
public static String HumanSize(UInt64 bytes)
    => Enumerable
    .Range(0, prefixes.Length)
    .Where(i => bytes < 1024U<<(i*10))
    .Select(i => $"{(bytes>>(10*i-10))/1024:0.###} {prefixes[i]}B")
    .First();

或者,如果你想减少LINQ对象的分配,使用相同的for循环变量:

/// <summary>
/// Returns the human-readable file size for an arbitrary, 64-bit file size.
/// </summary>
public static String HumanSize(UInt64 bytes)
{
    const String prefixes = " KMGTPEY";
    for (var i = 0; i < prefixes.Length; i++)
        if (bytes < 1024U<<(i*10))
            return $"{(bytes>>(10*i-10))/1024:0.###} {prefixes[i]}B";

    throw new ArgumentOutOfRangeException(nameof(bytes));
}

我使用下面的Long扩展方法将其转换为人类可读的大小字符串。这个方法是在Stack Overflow上发布的相同问题的Java解决方案的c#实现。

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

我喜欢使用以下方法(它支持高达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)编写的,因此对于较早的版本可能需要进行一些编辑。