- 开发工具
【免费下载链接】Humanizer
Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities
导读
ByteSizeExtensions是 Humanizer 中面向字节量(ByteSize)的一组静态扩展方法,解决了 .NET 开发中两个高频痛点:把裸露的数值转换为带单位的ByteSize值(如1024.Bytes()),以及把ByteSize输出为"2 GB"、"10.5 KB"这类人类可读的字符串。本指南以 Humanizer 3.0.1 官方 API 文档 Humanizer.ByteSizeExtensions.md 为骨架,结合仓库源码与测试,完整讲解每一个扩展方法的签名、语义、底层换算原理,以及如何用Per方法计算传输速率。读完本文,你将能直接在自己的 .NET 项目中用这些方法完成文件大小展示、日志格式化与网速统计等场景。
一、类概览:ByteSizeExtensions 是什么
ByteSizeExtensions是定义在Humanizer命名空间下的一个静态类,官方文档对其定位只有一句话:"Provides extension methods for ByteSize"(为ByteSize提供扩展方法)。它继承自System.Object,声明如下:
public static class ByteSizeExtensions在仓库源码 ByteSizeExtensions.cs 中可以看到,该类的实现方式是"每个扩展方法都是对ByteSize静态工厂方法的薄封装"——例如Kilobytes(this int input)内部直接返回ByteSize.FromKilobytes(input)。这意味着扩展方法本身不承载换算逻辑,真正的单位换算与数值存储全部集中在ByteSize结构体内部,扩展方法只是提供了一套流畅的、链式友好的调用语法。
使用这些扩展方法不需要额外配置,只要引入Humanizer命名空间即可:
using Humanizer; // 直接把数值"当作"某单位,得到 ByteSize 实例 ByteSize size = 10.Kilobytes();二、单位换算扩展方法:把数值"当作"某单位
文档核心部分是 6 组单位扩展方法:Bits、Bytes、Kilobytes、Megabytes、Gigabytes、Terabytes。它们语义统一:"Considers input as bits / bytes / kilobytes / ..."(把输入当作比特 / 字节 / 千字节……),并返回ByteSize。
2.1 方法签名与重载矩阵
每组单位方法都针对多种数值类型提供了重载,覆盖 .NET 全部常见整数类型与double。以文档完整列出的签名为准,方法族如下:
| 单位方法 | 支持的输入类型(this参数) | 内部实现 |
|---|---|---|
Bits(...) | byte、sbyte、short、ushort、int、uint、long | ByteSize.FromBits(input) |
Bytes(...) | byte、sbyte、short、ushort、int、uint、long、double | ByteSize.FromBytes(input) |
Kilobytes(...) | byte、sbyte、short、ushort、int、uint、long、double | ByteSize.FromKilobytes(input) |
Megabytes(...) | 同上 8 种类型 | ByteSize.FromMegabytes(input) |
Gigabytes(...) | 同上 8 种类型 | ByteSize.FromGigabytes(input) |
Terabytes(...) | 同上 8 种类型 | ByteSize.FromTerabytes(input) |
签名示例(文档中的原始声明):
public static Humanizer.ByteSize Bits(this byte input); public static Humanizer.ByteSize Bytes(this double input); public static Humanizer.ByteSize Kilobytes(this long input); public static Humanizer.ByteSize Megabytes(this uint input); public static Humanizer.ByteSize Gigabytes(this short input); public static Humanizer.ByteSize Terabytes(this sbyte input);值得注意:Bits不提供double重载,而Bytes到Terabytes均提供double重载。从源码看,这是因为ByteSize内部以"位"为原子单位存储(见下文 2.3),Bits面向整数值设计,而字节级单位天然需要支持小数(如 1.5 KB)。
2.2 从源码结构看:当前版本还包含更多单位
3.0.1 API 文档只收录了上述 6 组方法,但当前仓库源码 ByteSizeExtensions.cs 中,同一模式还扩展到了更大的单位与 IEC 二进制单位:Petabytes、Exabytes、Pebibytes(均提供byte到long及double重载),分别对应ByteSize.FromPetabytes、ByteSize.FromExabytes、ByteSize.FromPebibytes。从源码结构看,可以推断这些是文档版本之后陆续加入的 API,用法与旧单位完全一致:
ByteSize huge = 2.Exabytes(); // 2 * 10^18 字节 ByteSize iec = 5.Pebibytes(); // 5 * 2^50 字节2.3 底层换算原理:ByteSize 的存储模型
要正确使用这些扩展方法,必须理解ByteSize的内部存储。在 ByteSize.cs 中,ByteSize是一个结构体,核心状态只有两个:double byteSize(字节数)和long Bits(位数,向上取整得到):
public struct ByteSize(double byteSize) { public long Bits { get; } = (long)Math.Ceiling(byteSize * BitsInByte); public double Bytes { get; } = byteSize; // ... }换算常量(ByteSize.cs):
public const long BitsInByte = 8; public const long BytesInKilobyte = 1024; // 即 1 KiB public const long BytesInMegabyte = 1048576; // 即 1 MiB public const long BytesInGigabyte = 1073741824; // 即 1 GiB public const long BytesInTerabyte = 1099511627776; // 即 1 TiB public const long BytesInPetabyte = 1000000000000000; // 10^15(十进制) public const long BytesInExabyte = 1000000000000000000; // 10^18(十进制)由这些常量可以得出几个关键事实:
- KB/MB/GB/TB 采用 1024 进制(即与 KiB/MiB/GiB/TiB 数值等价,源码中
BytesInKibibyte等常量直接复用旧值),而PB/EB 采用 1000 进制——这正是ByteSizeUnitSystem.Legacy所描述的"混合单位"行为(见第四节)。 - 各
FromXxx工厂方法只是乘法:FromKilobytes(value)即new(value * BytesInKilobyte)。测试 CreatingTests.cs 验证了换算结果,例如ByteSize.FromKilobytes(1.5)得到1536字节,ByteSize.FromGigabytes(1.5)得到1610612736字节。 Bits属性对byteSize * 8做Math.Ceiling向上取整(源码注释 "Get ceiling because bits are whole units"),因此ByteSize.FromBytes(1.5)的Bits为 12(测试 CreatingTests.cs 验证)。
2.4 单元测试验证
创建类测试 CreatingTests.cs 对ByteSize的工厂方法与单位换算做了完整的断言验证,例如构造new ByteSize(1099511627776)(1 TB)后,其Kilobytes、Megabytes、Gigabytes、Terabytes属性分别为 1073741824、1048576、1024、1,直观印证了 1024 进制换算链。这些测试同样适用于通过扩展方法创建的ByteSize实例,因为两者最终都收敛到相同的工厂方法。
三、Humanize 方法:把 ByteSize 变成"2 GB"
Humanize是ByteSizeExtensions中最重要的格式化方法,文档对它的描述是:"Turns a byte quantity into human readable form, eg 2 GB"(把字节量转换为人类可读形式,如 2 GB)。
3.1 三个重载的完整签名
文档完整列出了三个重载:
// 重载 1:只指定格式字符串,format 可空(默认 null) public static string Humanize(this Humanizer.ByteSize input, string? format = null); // 重载 2:指定格式字符串 + 格式提供器 public static string Humanize(this Humanizer.ByteSize input, string? format, System.IFormatProvider? formatProvider); // 重载 3:只指定格式提供器 public static string Humanize(this Humanizer.ByteSize input, System.IFormatProvider formatProvider);参数说明:
| 参数 | 类型 | 含义 |
|---|---|---|
input | ByteSize | 要格式化的字节量 |
format | string? | 使用的字符串格式,如"0.00"、"KB"、"#.## GB";为null或空白时使用ByteSize默认格式 |
formatProvider | IFormatProvider? | 数字格式化提供器(如特定CultureInfo),影响数字的小数点、千位分隔符等 |
源码实现(ByteSizeExtensions.cs)非常直白,本质是把参数转发给ByteSize.ToString:
public static string Humanize(this ByteSize input, string? format = null) => string.IsNullOrWhiteSpace(format) ? input.ToString() : input.ToString(format); public static string Humanize(this ByteSize input, IFormatProvider formatProvider) => input.ToString(formatProvider); public static string Humanize(this ByteSize input, string? format, IFormatProvider? formatProvider) => string.IsNullOrWhiteSpace(format) ? input.ToString(formatProvider) : input.ToString(format, formatProvider);3.2 默认行为:自动选择最大的整数单位
不带format调用Humanize()(或ToString())时,ByteSize会自动选取最大的、数值绝对值不小于 1 的单位来展示。这一点在 ByteSize.cs 的GetLargestWholeNumberSymbol/LargestWholeNumberValue中实现:从 EB 开始逐级向下检查,直到Math.Abs(该单位值) >= 1。
测试 ToStringTests.cs 给出了明确的行为证据:
// 默认格式输出 Assert.Equal("10.5 KB", ByteSize.FromKilobytes(10.5).ToString()); // 自动降级到 KB(512 KB 而非 0.5 MB) Assert.Equal("512 KB", ByteSize.FromMegabytes(.5).ToString("#.#")); // 负值同样自动选单位 Assert.Equal("-512 KB", ByteSize.FromMegabytes(-.5).ToString("#.#"));3.3 自定义 format 字符串的规则
format参数既可以是纯数字格式,也可以包含单位 token。由 ByteSize.cs 的ToString(string?, IFormatProvider?)实现可知:
format为null或"G"时,统一替换为"0.##"(最多保留两位小数)。- format 中不含
#或0时,会被当作纯单位 token,自动拼接为"0.## " + format。例如Humanize("KB")等价于"0.## KB",测试ReturnsDefaultNumberFormat验证10.5.Kilobytes().Humanize("KB")输出"10.5 KB"。 - format 中含单位 token 时,按 token 匹配对应单位并输出该单位下的数值。
KB、MB、GB、TB、PB、EB及KiB、MiB、GiB、TiB、PiB的匹配不区分大小写,但b(bit)与B(byte)严格区分大小写(源码注释明确 "Byte and Bit symbol look must be case-sensitive")。 #.##会被规范化替换为0.##,保证自定义格式下小数位行为一致。
测试验证(ToStringTests.cs):
// 自定义数字精度 Assert.Equal("10.1234 KB", ByteSize.FromKilobytes(10.1234).ToString("#.#### KB")); // 指定单位输出 Assert.Equal("10 b", ByteSize.FromBits(10).ToString("##.#### b")); Assert.Equal("10 B", ByteSize.FromBytes(10).ToString("##.#### B")); Assert.Equal("10 MB", ByteSize.FromMegabytes(10).ToString("##.#### MB")); Assert.Equal("10 TB", ByteSize.FromTerabytes(10).ToString("##.#### TB")); // 指定精度的固定格式 Assert.Equal("10.0 TB", ByteSize.FromTerabytes(10).ToString("0.0 TB"));3.4 语言与区域设置(formatProvider)
formatProvider控制数字本身的格式化(如小数点是.还是,),同时参与单位词的本地化。从源码看,当传入CultureInfo时,数字格式会经过LocaleNumberFormattingOverrides.GetFormattingNumberFormat的覆盖处理,单位符号则由Configurator.GetFormatter(culture)解析的 Formatter 提供(ByteSize.cs)。这意味着Humanize输出的数字与单位都具备区域感知能力,适合直接用于多语言 UI。
四、Per 方法:从字节量到传输速率
Per是文档收录的最后一个扩展方法,用于把"某段时间内的字节量"转换为可操作的速率对象:
public static Humanizer.ByteRate Per(this Humanizer.ByteSize size, System.TimeSpan interval);参数语义(文档原文):
| 参数 | 含义 |
|---|---|
size | Quantity of bytes(字节数量) |
interval | Interval to create rate for(创建速率所依据的时间间隔) |
源码实现(ByteSizeExtensions.cs)只是构造了一个ByteRate:
public static ByteRate Per(this ByteSize size, TimeSpan interval) => new(size, interval);4.1 ByteRate 与 Humanize
ByteRate(ByteRate.cs)持有Size与Interval两个属性,并提供Humanize方法计算速率。默认按"每秒"输出,也支持TimeUnit.Minute、TimeUnit.Hour,但注意只支持这三者,其余时间单位会抛出NotSupportedException(测试ThrowsOnUnsupportedData验证):
public string Humanize(TimeUnit timeUnit = TimeUnit.Second) => Humanize(null, timeUnit); public string Humanize(string? format, TimeUnit timeUnit = TimeUnit.Second, CultureInfo? culture = null) { var displayInterval = timeUnit switch { TimeUnit.Second => TimeSpan.FromSeconds(1), TimeUnit.Minute => TimeSpan.FromMinutes(1), TimeUnit.Hour => TimeSpan.FromHours(1), _ => throw new NotSupportedException("timeUnit must be Second, Minute, or Hour"), }; return new ByteSize(Size.Bytes / Interval.TotalSeconds * displayInterval.TotalSeconds) .Humanize(format, culture) + '/' + timeUnit.ToSymbol(culture); }典型用法与测试期望(ByteRateTests.cs):
// 400 字节 / 1 秒 → "400 B/s" ByteSize.FromBytes(400).Per(TimeSpan.FromSeconds(1)).Humanize(); // 4 MB 数据用了 2 秒 → "4 MB/s" ByteSize.FromBytes(4 * 1024 * 1024).Per(TimeSpan.FromSeconds(2)).Humanize(); // 15 MB 数据用了 60 秒 → "15 MB/s" ByteSize.FromBytes(15 * 60 * 1024 * 1024).Per(TimeSpan.FromSeconds(60)).Humanize();按分钟/小时展示的示例(TimeUnitTests):
// 1 MB 在 60 秒内传完,按分钟展示 → "1 MB/min" ByteSize.FromMegabytes(1).Per(TimeSpan.FromSeconds(60)).Humanize(TimeUnit.Minute); // 按小时展示 → "1 MB/h" ByteSize.FromMegabytes(1).Per(TimeSpan.FromSeconds(3600)).Humanize(TimeUnit.Hour);ByteRate.ToString()直接委托给Humanize()(默认每秒速率),因此ByteSize.FromBytes(400).Per(TimeSpan.FromSeconds(1)).ToString()输出"400 B/s"。
4.2 速率对象还支持比较与相等判断
从 ByteRate.cs 可以看到,ByteRate实现了IComparable<ByteRate>与IEquatable<ByteRate>,比较和相等判断都基于归一化后的每秒字节数BytesPerSecond(Size.Bytes / Interval.TotalSeconds)。测试验证:400 B/10s 与 800 B/20s 归一化后相等,CompareTo返回 0;不同速率的比较结果符合预期。这让ByteRate可以直接放入SortedSet、用于排序或去重。
五、进阶:显式单位系统与复合格式(当前源码新增 API)
3.0.1 文档之外,当前仓库源码还提供了两组与Humanize同族的高阶扩展,属于同一主题的自然延伸,一并说明:
5.1 HumanizeWithUnitSystem:显式选择单位体系
ByteSizeUnitSystem(ByteSizeUnitSystem.cs)定义了三种单位体系:
| 枚举值 | 含义 |
|---|---|
Legacy = 0 | Humanizer 传统混合单位:KB~TB 用 1024 进制,PB/EB 用 1000 进制 |
DecimalSi = 1 | 十进制 SI 单位,相邻单位之间为 1000 倍 |
BinaryIec = 2 | 二进制 IEC 单位,相邻单位之间为 1024 倍(KiB/MiB/GiB...) |
对应的扩展方法HumanizeWithUnitSystem(this ByteSize, ByteSizeUnitSystem, string? format = null, IFormatProvider? formatProvider = null)(ByteSizeExtensions.cs):当传入Legacy时退化为普通Humanize,否则调用ByteSize.Format按显式单位体系格式化;若unitSystem未定义则抛ArgumentOutOfRangeException,format 非法则抛FormatException。
5.2 HumanizeComposite / HumanizeCompositeWithUnitSystem:复合格式输出
这两个方法(ByteSizeExtensions.cs)把字节量拆成多个降序单位输出,例如10 KB 2 B:
public static string HumanizeComposite( this ByteSize input, int precision = 2, IFormatProvider? formatProvider = null, string separator = " ", bool toWords = false)precision:最多返回的非零部分数量,必须 ≥ 1,否则抛ArgumentOutOfRangeException;separator:各部分之间的分隔符,默认空格,不允许null;toWords:为true时使用本地化单位单词(如 "kilobyte")而非符号(如 "KB");- 内部从 EB 逐级向下拆分,剩余的不足 1 字节的位以
Bit收尾。
HumanizeCompositeWithUnitSystem则叠加了DecimalSi/BinaryIec显式单位体系选择(内部维护DecimalCompositeUnits与BinaryCompositeUnits两组单位表,分别以 kB/MB/GB/TB/EB 和 KiB/MiB/GiB/TiB/PiB 递降)。相关行为由 ByteSizeUnitSystemTests.cs 与 ByteSizeMultiSectionFormatTests.cs 覆盖验证。
六、实战示例:组合使用
把扩展方法与Per串联,可以实现典型的"文件大小 + 传输速率"场景:
using Humanizer; // 1) 展示文件大小:自动选单位 long fileBytes = 13_107_200; Console.WriteLine(fileBytes.Bytes().Humanize()); // "12.5 MB" // 2) 强制单位与精度 Console.WriteLine(fileBytes.Bytes().Humanize("#.## MB")); // "12.5 MB" // 3) 指定区域格式(数字使用逗号小数点的区域) var de = CultureInfo.GetCultureInfo("de-DE"); Console.WriteLine(fileBytes.Bytes().Humanize(de)); // 数字按 de-DE 规则输出 // 4) 下载速率:500 MB 用了 32 秒 var size = 500.Megabytes(); var interval = TimeSpan.FromSeconds(32); Console.WriteLine(size.Per(interval).Humanize()); // "15.6 MB/s" Console.WriteLine(size.Per(interval).Humanize(TimeUnit.Minute)); // 按分钟换算七、小结
ByteSizeExtensions是 Humanizer 字节能力的前端入口,其设计呈现清晰的层次:
- 构造层:
Bits/Bytes/Kilobytes/Megabytes/Gigabytes/Terabytes(及源码中扩展的Petabytes/Exabytes/Pebibytes)把裸数值包装成带单位的ByteSize; - 格式化层:
Humanize系列方法自动选取最大的整数单位输出,并支持自定义数字格式、单位 token 与区域提供器; - 速率层:
Per+ByteRate把"字节量 + 时间间隔"变为可比较、可排序、可本地化的传输速率; - 进阶层:
HumanizeWithUnitSystem与HumanizeComposite(WithUnitSystem)提供显式单位体系与复合格式的精细控制。
所有行为均有源码与测试佐证:单位换算逻辑见 ByteSize.cs,扩展方法实现见 ByteSizeExtensions.cs,速率对象见 ByteRate.cs,行为断言见 CreatingTests.cs、ToStringTests.cs 与 ByteRateTests.cs。在你的项目里引入 Humanizer 包后,这些扩展方法即可直接使用,无需任何初始化配置。
- 开发工具
【免费下载链接】Humanizer
Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities
相关推荐
Humanizer ByteSizeExtensions 完全指南:.NET 字节与位单位转换、人性化格式化与速率计算的扩展方法全景
Humanizer ByteSizeExtensions 完全指南:.NET 字节与位单位转换、人性化格式化与速率计算的扩展方法全景 本篇技术指南围绕 Huma
开发工具Humanizer ByteSizeExtensions 扩展方法完全指南:字节单位构建、人类可读格式化与传输速率计算
Humanizer ByteSizeExtensions 扩展方法完全指南:字节单位构建、人类可读格式化与传输速率计算 Humanizer 的 ByteSize
开发工具Humanizer ByteSizeExtensions 扩展方法全解析:位、字节与传输速率的人性化展示
Humanizer ByteSizeExtensions 扩展方法全解析:位、字节与传输速率的人性化展示 Humanizer 是 .NET 生态中专注于字符串、
开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考