文件辅助

基本信息

属性 值
类 com.github.lunatrius.core.util.FileUtils
成员形式 全部 public static
引用来源 两处方法均标注了来源链接注释(StackOverflow)

grep -rn "FileUtils" 在 src/main/java/ 下只命中它自己的第 8 行声明,本 mod 内部零调用,是纯粹的公共 API。

人类可读字节数

签名 public static String humanReadableByteCount(final long bytes)

实现要点

步骤 源码
单位 final int unit = 1024;
小于 1024 return bytes + " B";
指数 int exp = (int) (Math.log(bytes) / Math.log(unit));
前缀字符 final String pre = "KMGTPE".charAt(exp - 1) + "i";
格式化 String.format("%3.0f %sB", bytes / Math.pow(unit, exp), pre)

输出对照

bytes 返回值 说明
0 0 B 走小于 1024 分支
1023 1023 B 走小于 1024 分支
1024 1 KiB exp = 1 → "KMGTPE".charAt(0) + "i"
1048576 1 MiB exp = 2 → charAt(1) + "i"
1073741824 1 GiB exp = 3
1099511627776 1 TiB exp = 4
1125899906842624 1 PiB exp = 5
1152921504606846976 1 EiB exp = 6 → charAt(5)

[!NOTE] 前缀带 i 后缀(IEC 风格),但基数用的是 1024 而非 1000;输出格式 %3.0f 会在数字前补空格凑满 3 字符宽度。exp 最大为 6(long 上限),"KMGTPE" 恰好 6 个字符,不会越界。

路径包含检查

签名 说明
public static boolean contains(final File root, final String filename) 委托 contains(root, new File(root, filename))
public static boolean contains(final File root, final File file) 比较 file.getCanonicalPath().startsWith(root.getCanonicalPath() + File.separator)

行为细节

情况 结果
file 确实是 root 下的子路径 true
file 就是 root 本身 false(因要求以 root + File.separator 开头)
file 是 root 的兄弟目录且同前缀 false(File.separator 边界检查正好拦住 /root2)
getCanonicalPath() 抛 IOException 捕获后 Reference.logger.error("", e) 并 return false

[!IMPORTANT] 用的是 getCanonicalPath() 而非 getAbsolutePath(),因此符号链接会被解析,.. 也会被折叠——这正是防目录穿越(path traversal)需要的语义。

[!WARNING] catch 块里 Reference.logger.error("", e) 的消息字符串是空字符串,IOException 只作为 throwable 附在日志堆栈里,因此按消息过滤日志时看不到任何线索。

相关条目