go标准库无内置文件大小人类可读格式转换函数,需自实现;推荐用二进制单位(kib/mib等)、整数判断+条件格式化,避免浮点误差与单位混淆。

Go 标准库没有内置的文件大小人类可读格式转换函数,fmt 和 bytes 包都不提供类似 Python 的 humanize.naturalsize 或 JavaScript 的 filesize 功能。必须自己写,但不用重造轮子——关键在于单位换算逻辑是否严谨、边界是否处理得当。
为什么不能直接用 1024 进制硬除?
常见错误是简单地用 size / 1024、/ 1024 / 1024 循环,忽略两个事实:一是二进制单位(KiB、MiB)和十进制单位(KB、MB)在不同场景下语义不同;二是浮点精度和舍入方式影响可读性。比如 1024 * 1024 - 1 字节(即 1048575)应该显示为 "1024 KiB" 而不是 "1.00 MiB",否则会误导用户以为已跨单位阈值。
- Linux
ls -lh默认用二进制前缀(KiB/MiB/GiB),且保留一位小数,但时不加单位 - Go 的
filepath.Walk返回的os.FileInfo.Size()是int64,需防溢出和负值 - 用
float64计算易引入0.1 + 0.2 != 0.3类误差,建议用整数倍数判断 + 条件格式化
如何写出兼容 ls -lh 行为的转换函数?
核心是定义单位序列和阈值,用整除+余数控制显示精度。推荐使用二进制单位(IEC 60027-2),因为文件系统天然基于 2^10:
func humanSize(size int64) string {
if size = unit && i
- 输入
size必须是int64,避免传入uint64导致负数误判 - 循环中用
f >= unit判断,而非f > unit,确保1024显示为"1 KiB"而非"1024 B" -
math.Floor(f) == f比f == float64(int64(f))更安全,防止大数值因精度丢失误判
为什么用 Sprintf 而不是 strconv?
格式化字符串比手动拼接 strconv 更简洁,且 fmt.Sprintf 对浮点数的 .1f 处理已足够稳定。但要注意:%.1f 在 Go 1.19+ 中对 0.05 会四舍五入为 0.1,符合常规预期;若需银行家舍入(偶数舍入),得自己实现。
- 不要用
fmt.Sprintf("%v %s", f, units[i]),它不控制小数位数,1025可能输出"1.001953125 KiB" - 避免用
strings.TrimSuffix去掉.0,不如用math.Floor判断更直观 - 如果项目要求十进制单位(KB/MB),把
unit改成1000即可,但需同步改单位名,且注意 POSIX 工具如du -h默认仍是二进制
真正难的不是写几行代码,而是决定“1024 字节该叫 1 KiB 还是 1 KB”,以及当 size 接近 PiB 量级时,float64 是否还能精确表示整数部分——这时候就得切回整数运算或用 big.Int,但绝大多数文件场景下,float64 足够覆盖到 ~9E15 字节(即约 9 PiB),已远超单文件常见上限。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











