如何删除嵌套文件夹中的指定文件(Node.js+Express场景)
Node.js+Express 删除嵌套目录本地文件路径问题解决
问题场景
在Node.js+Express项目中,需要先删除数据库中指定文件的记录,再删除uploads目录下嵌套子文件夹中的对应本地文件。但使用fs.unlinkSync、fs.access等方法时始终报错,核心问题是生成的文件路径错误,无法匹配到目标文件。
用户原代码:
import Express from 'express'; import { baseURL } from '..'; import fs from 'fs'; import path from 'path'; import { GuestFile } from '../models/guest-file'; export const GuestDelete = async (request: Express.Request, response: Express.Response) => { const { identifier } = request.params; const find_file = await GuestFile.findOne({ identifier }); if (!find_file) { return response.status(404).json({ error: 'File not found', success: false }); } const local_file_path = find_file.file_url?.split(`${baseURL}`).pop(); const file_name = local_file_path?.split('/')?.splice(-1)[0]; // 问题出在这里 fs.readdirSync(path.join(__dirname + `/uploads/${find_file.type}s/`)).find((file) => console.log(file)); console.log('file_name', file_name); response.status(204).json({ success: true, identifier }); };
曾尝试的无效代码:
fs.readdirSync('/uploads/${find_file.type}/').find((file) => file === file_name && fs.unlinkSync(file_name));
当前生成的错误路径:
C:\Users\essel_r\Desktop\everfile\backend_api\src\controllers\uploads\images\
目录结构说明:项目根目录为everfile/backend_api,uploads目录直接位于根目录下(而非src/controllers子目录中),uploads下按文件类型分了子文件夹(比如images)。
错误原因
- 路径拼接错误:
__dirname指向当前控制器文件所在的src/controllers目录,直接拼接/uploads/...会把uploads放到controllers目录下,与实际目录结构不符。 - 相对路径使用错误:直接用
/uploads/${find_file.type}/是系统根目录的绝对路径,而非项目根目录下的uploads。 - 删除文件时路径不完整:调用
fs.unlinkSync(file_name)只传了文件名,没有完整的文件路径,导致系统找不到文件。
解决方案
步骤1:正确获取项目根目录下的uploads路径
利用path.resolve从当前文件向上回溯到项目根目录,再拼接uploads和类型子文件夹。
步骤2:拼接完整的目标文件路径
结合类型子文件夹和文件名,生成完整的本地文件路径。
步骤3:检查文件存在后再删除
先使用fs.existsSync检查文件是否存在,避免删除不存在的文件报错。
步骤4:删除数据库记录(可根据业务调整执行顺序)
修改后的完整代码:
import Express from 'express'; import { baseURL } from '..'; import fs from 'fs'; import path from 'path'; import { GuestFile } from '../models/guest-file'; export const GuestDelete = async (request: Express.Request, response: Express.Response) => { const { identifier } = request.params; try { // 查询数据库记录 const find_file = await GuestFile.findOne({ identifier }); if (!find_file) { return response.status(404).json({ error: '文件不存在', success: false }); } // 解析文件名(从file_url中提取) const local_file_path = find_file.file_url?.split(`${baseURL}`).pop(); const file_name = local_file_path?.split('/')?.pop(); if (!file_name) { return response.status(400).json({ error: '文件路径解析失败', success: false }); } // 生成正确的本地文件目录路径 // 从当前文件(src/controllers)向上两级到项目根目录,再拼接uploads和类型子文件夹 const uploadsDir = path.resolve(__dirname, '../../uploads', `${find_file.type}s`); // 生成完整的文件路径 const fullFilePath = path.join(uploadsDir, file_name); // 检查文件是否存在并删除 if (fs.existsSync(fullFilePath)) { fs.unlinkSync(fullFilePath); } else { console.warn(`文件 ${fullFilePath} 不存在,跳过删除`); } // 删除数据库记录 await GuestFile.deleteOne({ identifier }); return response.status(200).json({ success: true, identifier }); } catch (error) { console.error('删除文件或数据库记录失败:', error); return response.status(500).json({ error: '服务器内部错误', success: false }); } };
关键说明
- 使用
path.resolve和path.join拼接路径,避免Windows与Linux路径分隔符的兼容性问题。 - 增加异常捕获,处理文件删除或数据库操作时的错误,避免服务崩溃。
- 可根据业务需求调整流程顺序:比如先删数据库记录再删文件,但需考虑失败场景的回滚逻辑。
内容的提问来源于stack exchange,提问作者Rocky Essel
相关产品推荐
相关产品推荐

