
本文介绍如何使用 Java 的共享文件锁(shared lock)实现对文件的保护:阻止其他进程删除文件,同时不影响其被正常读取或复制,通过 lock() 和 unlock() 方法封装控制逻辑。
本文介绍如何使用 java 的共享文件锁(shared lock)实现对文件的保护:阻止其他进程删除文件,同时不影响其被正常读取或复制,通过 `lock()` 和 `unlock()` 方法封装控制逻辑。
在 Windows 系统中,文件能否被删除取决于其是否被任何进程以独占(exclusive)方式打开。若一个进程以写入模式(如 "rw")获取了 FileChannel 并加锁,该锁默认为排他锁(exclusive),不仅会阻止其他进程修改/写入,还会导致 Windows 拒绝删除操作——同时也可能干扰复制行为(尤其在资源管理器等工具中,因部分复制流程会尝试临时独占打开源文件)。
而真正的解决方案是:仅以只读方式打开文件,并施加共享锁(shared lock)。共享锁允许多个进程同时持有,它不会阻止其他进程读取、复制,但能有效防止文件被删除(因为 Windows 要求文件在无任何打开句柄时才可删除;共享读锁即构成一个“打开句柄”)。
以下是推荐的实现方式:
✅ 正确做法:使用 FileChannel.open() + 共享锁(true 参数)
import java.io.IOException;
import java.nio.channels.*;
import java.nio.file.*;
import java.util.*;
public class FileGuard {
private static final Map<String, FileLock> activeLocks = new HashMap<>();
/**
* 对指定文件列表加共享读锁(防删除,不限制复制/读取)
*/
public static Map<String, FileLock> lockFiles(List<Path> paths) {
Map<String, FileLock> locks = new HashMap<>();
for (Path path : paths) {
try {
// 仅以 READ 模式打开,申请共享锁(第三个参数 true)
FileChannel channel = FileChannel.open(path, StandardOpenOption.READ);
FileLock lock = channel.lock(0, Long.MAX_VALUE, true); // 共享锁
locks.put(path.getFileName().toString(), lock);
activeLocks.put(path.toString(), lock);
System.out.println("✅ Shared lock acquired on: " + path);
} catch (IOException e) {
System.err.println("❌ Failed to lock " + path + ": " + e.getMessage());
}
}
return locks;
}
/**
* 释放指定锁并关闭对应通道
*/
public static void unlockFile(FileLock lock) {
if (lock == null || lock.isValid()) {
try {
lock.release();
lock.channel().close();
System.out.println("? Lock released");
} catch (IOException e) {
System.err.println("⚠️ Error releasing lock: " + e.getMessage());
}
}
}
/**
* 批量解锁(推荐用于 cleanup)
*/
public static void unlockAll() {
activeLocks.values().forEach(FileGuard::unlockFile);
activeLocks.clear();
}
}? 使用示例
public static void main(String[] args) {
List<Path> files = Arrays.asList(
Path.of("C:\Work\Test\a.txt"),
Path.of("C:\Work\Test\b.txt"),
Path.of("C:\Work\Test\c.txt")
);
Map<String, FileLock> locks = FileGuard.lockFiles(files);
// 模拟守护期(期间文件不可删除,但可复制、读取)
try {
Thread.sleep(15_000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 逐一释放
locks.forEach((name, lock) -> {
FileGuard.unlockFile(lock);
System.out.println(name + " unlocked");
try { Thread.sleep(5000); } catch (InterruptedException ignored) {}
});
}⚠️ 关键注意事项
- 仅 Windows 有效:该机制依赖 Windows 文件系统语义(删除需关闭所有句柄)。Linux/macOS 不强制要求“无打开句柄才能删除”,因此此方案主要适用于 Windows 环境。
-
锁生命周期绑定通道:
FileLock必须与FileChannel配合使用,且channel.close()后锁自动失效;务必确保unlockFile()中先release()再close()。 -
不要混用
RandomAccessFile和FileChannel.open():前者易误开写模式,后者更可控、更符合现代 NIO 最佳实践。 -
异常处理不可省略:I/O 操作必须捕获
IOException,避免锁泄漏;建议配合try-with-resources(如示例中FileChannel.open(...)可进一步优化为自动关闭)。 -
进程退出前务必调用
unlockAll():防止残留锁导致后续启动失败。
✅ 总结
要实现「防删除但允复制」,核心不是“加更强的锁”,而是“加更轻量、更兼容的锁”——即只读共享锁。它既满足操作系统级的删除防护要求,又完全兼容复制、备份、文本编辑器查看等常规操作。结合清晰的 lockFiles() / unlockFile() 封装,即可构建稳定可靠的文件保护模块。
立即学习“Java免费学习笔记(深入)”;


















