news 2026/9/28 2:47:53

Humanizer 字节大小扩展方法(ByteSizeExtensions)完整指南:单位换算、格式化与速率计算

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Humanizer 字节大小扩展方法(ByteSizeExtensions)完整指南:单位换算、格式化与速率计算
  • 开发工具

【免费下载链接】Humanizer

Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities

项目地址:https://gitcode.com/gh_mirrors/hu/Humanizer
点击查看免费下载

导读

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、longByteSize.FromBits(input)
Bytes(...)byte、sbyte、short、ushort、int、uint、long、doubleByteSize.FromBytes(input)
Kilobytes(...)byte、sbyte、short、ushort、int、uint、long、doubleByteSize.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(十进制)

由这些常量可以得出几个关键事实:

  1. KB/MB/GB/TB 采用 1024 进制(即与 KiB/MiB/GiB/TiB 数值等价,源码中BytesInKibibyte等常量直接复用旧值),而PB/EB 采用 1000 进制——这正是ByteSizeUnitSystem.Legacy所描述的"混合单位"行为(见第四节)。
  2. 各FromXxx工厂方法只是乘法:FromKilobytes(value)即new(value * BytesInKilobyte)。测试 CreatingTests.cs 验证了换算结果,例如ByteSize.FromKilobytes(1.5)得到1536字节,ByteSize.FromGigabytes(1.5)得到1610612736字节。
  3. 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);

参数说明:

参数类型含义
inputByteSize要格式化的字节量
formatstring?使用的字符串格式,如"0.00"、"KB"、"#.## GB";为null或空白时使用ByteSize默认格式
formatProviderIFormatProvider?数字格式化提供器(如特定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?)实现可知:

  1. format为null或"G"时,统一替换为"0.##"(最多保留两位小数)。
  2. format 中不含#或0时,会被当作纯单位 token,自动拼接为"0.## " + format。例如Humanize("KB")等价于"0.## KB",测试ReturnsDefaultNumberFormat验证10.5.Kilobytes().Humanize("KB")输出"10.5 KB"。
  3. 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")。
  4. #.##会被规范化替换为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);

参数语义(文档原文):

参数含义
sizeQuantity of bytes(字节数量)
intervalInterval 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 = 0Humanizer 传统混合单位: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

项目地址:https://gitcode.com/gh_mirrors/hu/Humanizer
点击查看免费下载

相关推荐

上一篇:1.8.2 - 2020-10-22
下一篇:AutoDock Vina批量对接教程:如何高效处理大规模配体库

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 2:45:32

银河麒麟V10 ARM64离线升级OpenSSH 10.0p2国密加固指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 2:44:08

中科蓝讯RISC-V开发环境搭建:CodeBlocks与RV32工具链配置指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 2:43:09

pixi auth 完全指南:为私有频道与上传服务配置登录凭证

开发工具CLI包管理器任务调度 【免费下载链接】pixi Powerful system-level package manager for Linux, macOS and Windows written in Rust – building on top of the Conda ecosystem. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/pi/pixi 点击查看 免费下载 导…

作者头像 李华