不会崩溃,没有“文件句柄耗尽”的限制,但是有“性能”和“业务逻辑”上的严重副作用。
我们来对比一下两种方案的区别,你就能明白为什么了:
1. 之前的方案 (fs.open / 文件句柄)
- 原理:程序必须“抓住”每一个文件(占用 1 个句柄)。
- node_modules:如果有 30,000 个文件,就要抓 30,000 次。
- 结果:崩溃。因为操作系统限制单个程序只能抓几千个。
2. 现在的方案 (icacls / 权限控制)
- 原理:程序只是对操作系统下达一个指令:“把这个文件夹及其子文件的属性改为不可写”。
- node_modules:即使有 30,000 个文件,Electron 也只是发出了一条命令。操作系统负责在底层修改元数据(Metadata)。
- 结果:不会崩溃。Electron 进程甚至不需要读取这些文件。
但是!虽然不会崩,我强烈建议你【依然要排除】它们
原因如下:
1. 性能问题 (时间成本)
虽然不会崩,但 icacls 递归修改 3 万个文件的权限需要时间。
- 现象:用户点击“打开工程”,界面可能会卡住 5~10 秒(视磁盘速度而定),直到命令执行完。这在用户体验上是不可接受的。
2. 业务逻辑冲突 (Git 和 NPM 瘫痪)
这是最致命的:
- 如果锁了
.git:你的 Git 就会报错 permission denied,你无法 commit,无法 checkout,Git 状态全乱。
- 如果锁了
node_modules:用户想运行 npm install 安装新包时,会直接报错,因为 NPM 无法写入那个文件夹。
- 如果锁了
dist:Webpack/Vite 无法打包,因为无法清理旧文件。
解决方案:优化 SecurityManager 以跳过特定目录
icacls 命令本身不支持“排除文件夹”的参数(它要么锁单个,要么 /T 递归锁全部)。
所以,我们需要在 Node.js 层面做一个**“智能遍历”**:
- 读取根目录下的第一层文件/文件夹。
- 如果是
node_modules 或 .git,直接跳过,不执行 icacls。
- 如果是其他文件夹(如
src),执行 递归 (/T) 锁定。
- 如果是文件(如
package.json),执行 单文件 锁定。
下面是优化后的 src/main/security-manager.ts 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
const IGNORE_DIRS = ['.git', 'node_modules', 'dist', 'build', '.vscode', '.idea']
export class SecurityManager {
async lockProject(dirPath: string) { this.rootPath = dirPath console.log(`🛡️ 正在开启独占模式 (智能排除): ${dirPath}`)
await this.applySmartLock(dirPath, true)
this.startSentry(dirPath) }
async unlockProject() { if (!this.rootPath) return console.log(`🔓 正在解除独占模式...`) if (this.watcher) { await this.watcher.close() this.watcher = null }
await this.applySystemLock(this.rootPath, false, true) this.rootPath = '' }
private async applySmartLock(basePath: string, isLock: boolean) { const items = await fs.readdir(basePath, { withFileTypes: true })
for (const item of items) { const fullPath = path.join(basePath, item.name)
if (IGNORE_DIRS.includes(item.name)) { console.log(`⏩ 跳过忽略目录: ${item.name}`) continue }
if (item.isDirectory()) { await this.applySystemLock(fullPath, isLock, true) } else { await this.lockSingleFile(fullPath) } } await this.lockSingleFile(basePath) }
private async applySystemLock(targetPath: string, isLock: boolean, recursive: boolean) { if (this.isWindows) { const perm = isLock ? '/deny Everyone:(OI)(CI)(DE,DC,WD,AD,WEA,WA)' : '/remove:d Everyone' const recursiveFlag = recursive ? '/T' : '' const cmd = `icacls "${targetPath}" ${perm} ${recursiveFlag} /C /Q` try { await execAsync(cmd) } catch (e) {}
} else { const perm = isLock ? 'a-w' : 'u+w' const recursiveFlag = recursive ? '-R' : '' const cmd = `chmod ${recursiveFlag} ${perm} "${targetPath}"` try { await execAsync(cmd) } catch (e) {} } }
}
|
总结
- 技术上:
icacls 方案没有文件数量限制,不会崩溃。
- 实际上:为了保证 Git 和 NPM 正常工作,以及打开工程时的速度,必须排除
node_modules 和 .git。
- 实现策略:“首层遍历 + 针对性递归”。即遍历根目录,跳过黑名单,对剩下的文件夹(如
src)进行全量递归锁定。这样既快又安全。
Prev: 兼容一键切换是否锁定文件夹
Next: 独占式文件锁定_icacls