Ubuntu环境下Node.js出现ENOENT错误,但目标文件实际存在
可能的原因及对应方案:
SMB文件系统的同步延迟
网络共享(SMB)的文件元数据同步存在延迟是常见问题。glob扫描到文件列表后,文件可能还没在底层文件系统完成写入就绪,这时候用fs.readFileSync读取就会触发ENOENT。而文件管理器通常会做缓存或延迟加载,所以能正常看到文件。
解决办法:给每个文件读取操作加重试机制,失败后等待几百毫秒再重试2-3次。示例代码:function readFileWithRetry(path, retries = 3, delay = 500) { try { return fs.readFileSync(path); } catch (err) { if (err.code === 'ENOENT' && retries > 0) { setTimeout(() => {}, delay); // 等待后重试 return readFileWithRetry(path, retries - 1, delay); } throw err; } }glob的实时性不足
glob默认仅基于目录条目返回文件列表,不会检查文件是否真的可访问。如果CCTV文件处于边写入边被扫描的状态(比如监控还在写入该文件),就会出现条目存在但无法读取的情况。
解决办法:在读取前先检查文件是否可读,用fs.accessSync做前置校验:for (const file of filesArr) { try { fs.accessSync(file, fs.constants.R_OK); // 检查文件可读权限 const data = fs.readFileSync(file); // 执行后续复制逻辑 } catch (err) { if (err.code === 'ENOENT') { console.log(`文件暂不可访问,跳过或稍后重试: ${file}`); } } }SMB挂载的稳定性问题
偶尔的网络波动可能导致SMB挂载点临时失去连接,此时读取文件会触发ENOENT。文件管理器通常会自动重新连接,但脚本不会主动处理这类情况。
解决办法:在脚本中加入挂载点连通性检查,比如定期读取挂载点下的固定测试文件;若捕获到ENOENT错误,可尝试重新挂载SMB共享(需sudo权限,适合受控运行环境)。文件路径的隐形问题
部分SMB共享可能返回带有不可见字符的文件名,或者路径大小写在SMB(大小写不敏感)与Ubuntu本地文件系统(大小写敏感)间存在差异,导致glob拿到的路径和实际可读路径不匹配。
解决办法:打印出错文件的路径,用console.log(Buffer.from(file).toString('hex'))排查是否有不可见字符;或读取前对路径做标准化处理:const normalizedPath = path.normalize(file);
内容的提问来源于stack exchange,提问作者seventeen

