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

How do I get a human-readable file size in bytes abbreviation using .NET?

如何使用.NET获取以字节缩写表示的可读文件大小?

例子:接收输入7326629并显示6.98 MB


这不是最有效的方法,但是如果你不熟悉对数数学,阅读起来就容易多了,而且对于大多数情况来说,速度应该足够快。

1
2
3
4
5
6
7
8
9
10
11
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]);


使用日志解决问题….

1
2
3
4
5
6
7
8
9
10
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位。

基本上确定以1024为基数的小数位数,然后除以1024的小数位数。

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

1
2
3
4
5
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

编辑:有人指出我错过了一个数学楼层,所以我把它合并了。(convert.toint32使用舍入,而不是截断,这就是为什么地板是必需的。)谢谢你的接球。

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


请求函数的测试和显著优化版本发布在这里:

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

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[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


另外一种方法是不使用任何类型的循环和负大小支持(对文件大小增量这样的事情很有意义):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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]);
    }
}

这是测试套件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[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);
    }
}

签出字节大小库。它是用于字节的System.TimeSpan

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

1
2
3
4
var maxFileSize = ByteSize.FromKiloBytes(10);
maxFileSize.Bytes;
maxFileSize.MegaBytes;
maxFileSize.GigaBytes;

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

1
2
3
4
5
6
7
8
// 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");


我喜欢使用以下方法(它最多支持兆字节,这对于大多数情况来说已经足够了,但是可以很容易地扩展):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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)编写的,因此可能需要对早期版本进行一些编辑。


1
2
3
4
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 );


1
2
3
4
5
6
7
8
9
10
11
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]);


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

1
2
3
4
5
6
7
8
9
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"代表位,"b"代表字节,"kmgtpezy"分别代表kilo、mega、giga、tera、peta、exa、zetta和yotta。

可以将其扩展到考虑到ISO/IEC80000:

1
2
3
4
5
6
7
8
9
10
11
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);
}


如果您试图匹配Windows资源管理器的详细信息视图中显示的大小,则需要以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
[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与以前的版本k=1024)。


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

1
2
3
4
5
6
7
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/字节大小

https://github.com/mehdik/humanizer


所有溶液的混合物:—)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    /// <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的解决方案。使用shift而不是division来测试bytes的范围,因为division需要更多的CPU成本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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]);
}

递归怎么样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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");
  }
}

然后你叫它:

1
return ReturnSize(size, string.Empty);


我假设您要查找的是"1.4 MB"而不是"1468006 bytes"?

我认为在.NET中没有一种内置的方法可以做到这一点。您只需确定哪个单元是合适的,并格式化它。

编辑:下面是一些示例代码:

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


还有一个方法,为了它的价值。我喜欢上面提到的@humbads优化解决方案,所以复制了这一原则,但我的实现方式有点不同。

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

关于单位,我认为我在我的生活中从来没有说过"kibibyte"或"mebibyte",虽然我对这种强制标准而不是进化标准持怀疑态度,但我认为从长远来看,它可以避免混淆。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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);
    }
}

我的2分钱:

  • 千字节的前缀是kb(小写k)
  • 由于这些功能是用于表示的,所以应该提供一种文化,例如:string.Format(CultureInfo.CurrentCulture,"{0:0.##} {1}", fileSize, unit);
  • 根据上下文,千字节可以是1000或1024字节。同样适用于MB、GB等。


我使用下面的long-extension方法转换为可读大小的字符串。该方法是在堆栈溢出上发布的同一问题的Java解决方案的C语言实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/// <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";
}