POST请求后无法删除被Read Stream占用的文件夹,求解决方案
解决Read Stream占用导致文件夹无法删除的问题
这种文件被流占用删不掉的情况我之前也碰到过,大概率是流的资源没有完全释放,或者销毁时机不对。结合你给出的代码和描述,咱们一步步来排查解决:
1. 别用全局变量管理流,改用请求上下文或映射表
全局变量file很容易出问题——如果多个用户同时请求视频流,后面的请求会覆盖前面的流引用,导致旧的流根本没被正确销毁。建议用Map来存储每个请求对应的流,比如:
// 全局维护一个流映射表,用请求的文件夹名称作为key const activeStreams = new Map(); app.get('/api/video/:folder', function(req, res) { const folder = req.params.folder; // 你代码里写的streamer应该是笔误,改成folder更合理 const path = `D:/Clips/${folder}/clip.mp4`; try { const stat = fs.statSync(path); const fileSize = stat.size; const range = req.headers.range; // 处理range请求(这里补全你没写完的逻辑) let start = 0; let end = fileSize - 1; if (range) { const parts = range.replace(/bytes=/, "").split("-"); start = parseInt(parts[0], 10); end = parts[1] ? parseInt(parts[1], 10) : end; } const chunksize = (end - start) + 1; // 创建读取流 const fileStream = fs.createReadStream(path, { start, end }); // 把流存入映射表 activeStreams.set(folder, fileStream); // 监听流的close事件,自动从映射表移除 fileStream.on('close', () => { activeStreams.delete(folder); }); // 监听error事件,避免流出错后残留引用 fileStream.on('error', (err) => { console.error('Stream error:', err); activeStreams.delete(folder); res.status(500).send('Stream error'); }); // 设置响应头并pipe流到响应 res.writeHead(206, { 'Content-Range': `bytes ${start}-${end}/${fileSize}`, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/mp4', }); fileStream.pipe(res); } catch (err) { console.error('Video request error:', err); res.status(404).send('Video not found'); } });
2. 销毁流后,必须等待close事件触发再删除文件夹
调用destroy()和unpipe()后,流不会立刻释放文件句柄,得等close事件确认资源完全释放后,再执行删除操作。比如你的POST请求处理逻辑可以改成这样:
app.post('/api/delete-folder', async function(req, res) { const folderToDelete = req.body.folder; const targetStream = activeStreams.get(folderToDelete); if (targetStream) { // 先销毁流并取消pipe targetStream.unpipe(); targetStream.destroy(); // 等待close事件触发,确保资源彻底释放 await new Promise((resolve) => { targetStream.once('close', resolve); }); } // 现在尝试删除文件夹 try { await fs.promises.rm(`D:/Clips/${folderToDelete}`, { recursive: true, force: true }); res.send('Folder deleted successfully'); } catch (err) { console.error('Delete folder error:', err); res.status(500).send('Failed to delete folder'); } });
3. 检查是否有未处理的流错误
如果流在读取过程中出现错误(比如文件突然损坏),但你没监听error事件,流会处于挂起状态,文件句柄也不会释放。所以一定要给每个流加上error事件监听,及时清理资源。
4. 确保响应对象的状态
有时候即使你销毁了流,响应对象res如果没正确结束,也可能导致资源泄漏。可以在销毁流后手动结束响应:
targetStream.destroy(); res.end();
按照上面的方法调整后,应该就能解决文件被占用无法删除的问题了。
内容的提问来源于stack exchange,提问作者sword1st
相关产品推荐
相关产品推荐

