文件辅助
基本信息
| 属性 | 值 |
|---|---|
| 类 | 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 附在日志堆栈里,因此按消息过滤日志时看不到任何线索。