Class AtomicFiles
各最终产物先写入「与目标同目录的唯一临时文件」,写完整后再用原子 move 落位。 这样跨 daemon 的无锁存在性检查不会在写入期间看到半成品:读方要么看到旧文件、要么看到完整的新文件。
Windows 的替换限制
POSIX 的 rename(2) 可以覆盖任何同名文件,但 Windows 不允许替换(或删除)正被其它句柄打开的文件:
只要读方还持有句柄,MoveFileEx(REPLACE_EXISTING) 就会以 ERROR_ACCESS_DENIED 失败,
Java 侧表现为 AccessDeniedException。实测 InputStream、FileChannel、
ZipFile 与 FileSystem(zipfs) 的读取句柄都会触发该限制。
因此 move(java.nio.file.Path, java.nio.file.Path) 对这种情况做「有上限的退避重试」:短生命周期的读方(例如反复读取的构建)会被自动让过,
持续占用则最终抛出带诊断信息的异常,而不是把平台限制原样丢给调用方。读方的不变量不受影响——
重试期间目标始终是旧的完整文件。
-
Nested Class Summary
Nested Classes -
Method Summary
Modifier and TypeMethodDescriptionstatic void便捷方法:原子复制一个已存在的源文件到 target.static void原子 move:优先 ATOMIC_MOVE,个别平台不支持时退化为普通 move.static voidpublish(Path target, AtomicFiles.IOConsumer<Path> producer) 原子发布:让 producer 把内容写入「同目录唯一临时文件」,写完后原子 move 到 target.static PathtempSibling(Path target) 为 target 生成一个同目录、唯一且尚不存在的临时路径(不创建文件).
-
Method Details
-
publish
原子发布:让 producer 把内容写入「同目录唯一临时文件」,写完后原子 move 到 target.临时文件用
Files.createTempFile(Path, String, String, java.nio.file.attribute.FileAttribute[])生成唯一名,避免并发写同一 target 时多个临时文件互相踩踏。无论成功失败,finally 都会清理临时文件。- Parameters:
target- 最终落位路径producer- 内容生产者,接收临时文件路径并把内容写进去- Throws:
IOException
-
tempSibling
为 target 生成一个同目录、唯一且尚不存在的临时路径(不创建文件).供「一次产生多个输出、不便用
publish(java.nio.file.Path, net.fabricmc.loom.util.cache.AtomicFiles.IOConsumer<java.nio.file.Path>)逐个包裹」的场景使用(例如 jar 拆分写两个文件): 调用方把内容写入这些临时路径后,用move(java.nio.file.Path, java.nio.file.Path)各自原子落位。 -
copy
便捷方法:原子复制一个已存在的源文件到 target.- Throws:
IOException
-
move
原子 move:优先 ATOMIC_MOVE,个别平台不支持时退化为普通 move.用于调用方已将内容写入同目录临时文件、需把其原子落位到 target 的场景 (例如一次产生多个输出、不便用
publish(java.nio.file.Path, net.fabricmc.loom.util.cache.AtomicFiles.IOConsumer<java.nio.file.Path>)逐个包裹时)。目标被其它进程/线程的读取句柄占用时(Windows 的替换限制,见类注释)会做有上限的退避重试, 让过短生命周期的读方;持续占用则抛出带诊断信息的
IOException。- Throws:
IOException
-