应统一使用1024进制换算,避免与操作系统显示不一致;需严格处理边界条件(如1024字节=1.00 KB)、小数精度及负数零值,推荐用1024.0除避免整数截断。

直接用 humanize.Bytes 最省事,但得引入第三方库;如果不想加依赖,手写转换函数也完全可行,关键是要统一单位标准、处理好边界和小数精度。
os.Stat 得到的字节数怎么转成 KB/MB/GB
从 os.Stat 拿到的 info.Size() 是 int64 字节数,转换时必须明确用 1024 进制(不是 1000),否则和操作系统显示不一致。比如 Windows 资源管理器、ls -lh 默认都按 KiB/MiB 算。
- 别用
float64(size) / 1000—— 这会和系统显示差 2.4%,用户一眼就能发现不对 - 推荐用
1024.0做除数,避免整数除法截断 - 单位阈值要严格:KB 是
< 1024 * 1024,不是<=,否则 1024 字节会显示为 "1.00 KB" 而不是 "1024 B" - 示例:1023 → "1023.00 B",1024 → "1.00 KB",1048575 → "1023.99 KB",1048576 → "1.00 MB"
为什么自己写转换函数容易出错
常见错误不是算法逻辑错,而是单位混淆 + 边界判断松动。比如:
-
if size < 1024*1024写成<=,导致 1 MiB 刚好卡在边界上显示异常 - 用
1000当基数,结果和du -h或资源管理器对不上 - 没处理负数或零值,
os.Stat在某些特殊文件(如设备节点)上可能返回 0,但业务上需过滤 - 小数位数硬写
"%.1f",遇到 999.999 会四舍五入成 "1000.0 KB",实际该进位到 MB
go-humanize.Bytes 是不是万能解
它省心,但要注意两点:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
立即学习“go语言免费学习笔记(深入)”;
- 默认用 IEC 标准(KiB/MiB),输出是
"1.2 KiB"而不是"1.2 KB"—— 如果 UI 要求显示 "KB" 字样,就得自己 post-process 字符串 - 不支持自定义小数位数,固定最多 2 位且自动省略尾随零(
humanize.Bytes(1024)返回"1 KiB",不是"1.00 KiB") - 对超大值(如接近
math.MaxInt64)的处理是安全的,内部用了log2分段,比手写 if-else 更健壮
批量统计目录总大小时怎么格式化
先用 filepath.WalkDir 遍历,累加所有 entry.Info().Size(),再统一格式化。别边遍历边格式化 —— 每次调用转换函数都有浮点运算开销,纯累加用 int64 更快。
- 记得跳过符号链接(
entry.Type()&fs.ModeSymlink != 0)和目录(entry.IsDir()),除非你真要算“目录项数量” - 权限错误时,
filepath.WalkDir的回调可返回filepath.SkipDir继续,别让整个遍历因单个无权目录中断 - 并发统计?用
atomic.Int64.Add替代普通变量,避免竞态,但注意filepath.WalkDir本身不是并发安全的,得自己拆任务
真正麻烦的不是换算本身,而是单位语义一致性:同一个数值,在磁盘占用、网络传输、UI 显示里可能对应不同标准。写之前先确认下游系统用哪一套,比写一百行代码还重要。

















