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); } } |
签出字节大小库。它是用于字节的
它为您处理转换和格式化。
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来测试
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"; } |