问答中心分类: VB.NET如何使用 .NET 以字节缩写形式获得人类可读的文件大小?
0
匿名用户 提问 7分钟 前

如何使用 .NET 以字节缩写形式获得人类可读的文件大小?
例子: 输入 7,326,629 并显示 6.98 MB

24 Answers
0
deepee1 回答 7分钟 前

使用日志解决问题….

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 字节大小的评论,所以我更新以处理这些情况。

IvanL 回复 7分钟 前

我想警告说,虽然这个答案确实是一小段代码,但它并不是最优化的。我想让你看看@humbads 发布的方法。我运行了微测试,通过这两种方法发送了 10 000 000 个随机生成的文件大小,这表明他的方法快了约 30%。然而,我对他的方法做了一些进一步的清理(不必要的任务和铸造)。此外,我运行了一个负大小的测试(当您比较文件时),而 humbads 的方法完美地处理了这个 Log 方法将引发异常!

dasheddot 回复 7分钟 前

是的,您应该为负尺寸添加 Math.Abs​​。此外,如果大小正好为 0,则代码不会处理这种情况。

Jayson Ragasa 回复 7分钟 前

Math.Abs​​、Math.Floor、Math.Log、转换为整数、Math.Round、Math.Pow、Math.Sign、加法、乘法、除法?这么多的数学运算不是对处理器造成了巨大的影响吗?这可能比@humbads 代码慢

BrunoLM 回复 7分钟 前

失败double.MaxValue(地点 = 102)

Djibril NDIAYE 回复 7分钟 前

效果很好!要模仿 Windows 的工作方式(至少在我的 Windows 7 终极版上),请将 Math.Round 替换为 Math.Ceiling。再次感谢。我喜欢这个解决方案。

0
humbads 回答 7分钟 前

此处发布了请求功能的经过测试和显着优化的版本:
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;
}
Jayson Ragasa 回复 7分钟 前

+1!更简单直接!使处理器更轻松、更快地进行数学运算!

Royi Namir 回复 7分钟 前

仅供参考,您不使用中的值double readable = (i < 0 ? -i : i);任何地方,所以删除它。还有一件事,演员阵容太强大了

humbads 回复 7分钟 前

我删除了演员表,添加了评论,并修复了带有负号的问题。

kspearrin 回复 7分钟 前

很好的答案。谢谢,为什么不直接使用Math.Abs?

humbads 回复 7分钟 前

(i < 0 ? -i : i) 比 Math.Abs​​ 快大约 15%。对于一百万次调用,Math.Abs​​ 在我的机器上慢了 0.5 毫秒——3.2 毫秒对 3.7 毫秒。

JohnC 回复 7分钟 前

应该是“MiB”、“KiB”等?

humbads 回复 7分钟 前

@JohnC,这取决于观众。我会坚持使用“MB”、“GB”等作为常用用法,如果受众非常技术性,如开发人员、工程师等,则将其更改为“MiB”、“GiB”等。

JohnC 回复 7分钟 前

也许两者都带有开关并使用 1024 或 1000 作为开关;我现在在“现实世界”中越来越多地看到 MiB

Otiel 回复 7分钟 前

使用 .NET Framework 4.6.1,Math.Abs10 亿次调用快 11 秒(14 秒而不是 3 秒)。

Basic 回复 7分钟 前

@humbads 根据我的经验,非技术用户将 GiB 理解为 Gigabyte,并在很大程度上忽略了i,所以使用正确的单位并没有真正的损失。

humbads 回复 7分钟 前

@Basic 同样,取决于上下文。我怀疑这个函数主要用于显示文件大小。无论我看到 1.073 GB 还是 1.000 GiB,我仍然会将其读作“1 GB”,我什至不会关心小数点后的数字。在这种情况下,“i”是多余的。

Basic 回复 7分钟 前

正是我的意思……对于那些不在乎的人来说,这没有什么区别,所以你最好按照正确的方式去做。

0
Bob 回答 7分钟 前
[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

Bart 回复 7分钟 前

我可能是个菜鸟,但使用像 pinvoke 这样的巨型大炮杀死那只鸭子是一个很大的误用。

Andrew 回复 7分钟 前

这是探索者使用的吗?如果是这样,那么对于让人们将您向他们显示的文件大小与资源管理器显示的文件大小相匹配非常有用。

Matthew Lock 回复 7分钟 前

并且不会重新发明轮子

Ray 回复 7分钟 前

11 个字符不是一个恒定的限制并且有点低吗?我的意思是,其他语言可能会使用更多字符作为字节大小首字母缩写词或其他格式样式。

Matthew Lock 回复 7分钟 前

@Bart 新手需要一段时间来学习这方面的智慧:“我们应该忘记小的效率,说大约 97% 的时间:过早的优化是万恶之源”ubiquity.acm.org/article.cfm?id=1513451

Bart 回复 7分钟 前

@Matthew 我知道这句话,这是我的最爱之一。但我评论的重点不是针对效率,而是针对纯度。在 PInvoke 上进行中继是我们安全管理世界中的最后也是终极武器。当我们为这项任务完美管理代码时,我们为什么要带来任何风险,即有一天这个外部函数会失败或被删除?我们应该依赖于此测试我们的代码吗?它会在Linux上工作吗?等等等等。这么多额外的问题,我认为投票得分最高的答案没有潜在的好处。

41686d6564 stands w. Palestine 回复 7分钟 前

@MatthewLock,嗯,这就像打电话计算20+15在你的脑海中,而不是伸手去拿计算器重新发明轮子。

Herohtar 回复 7分钟 前

这绝对是不是这样做的方法。如果您想完全匹配操作系统显示的大小,它可能在非常特定的情况下对仅限 Windows 的程序有一些用处;但是,在 Windows 10 中,该函数使用基数 10 而不是基数 2(1 KB = 1000 字节而不是 1024),因此相同的代码会根据运行的 Windows 版本产生不同的输出。最后,如果您正在编写跨平台代码,这完全没用。

0
Omar 回答 7分钟 前

结帐字节大小图书馆。这是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");
Larsenal 回复 7分钟 前

这是你自己的图书馆,不是吗?

Larsenal 回复 7分钟 前

在这样一个方便的图书馆里没有羞耻。 🙂

Theophilus 回复 7分钟 前

我印象深刻,@Omar。你写这个答案已经 8 年了,你还在维护你的图书馆。它也很受欢迎。NuGet报告 230 万次下载。

0
Constantin 回答 7分钟 前

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

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