Node.js中实现目录不存在则创建并保存前端传来的文件
Node.js 实现目录自动创建并保存前端上传文件
注意:你原代码里用了
d.getDay(),这个方法返回的是星期几(0-6,0代表周日),不是当月的日期,应该改成d.getDate()来获取当月的具体日期(1-31),否则目录结构会不符合预期。
先给你修正后的目录生成代码:
const fs = require('fs'); const d = new Date(); // 修正日期获取逻辑,生成按年/月/日/时/分/秒分层的目录 const directory = `./some-dir/${d.getFullYear()}/${String(d.getMonth() + 1).padStart(2, '0')}/${String(d.getDate()).padStart(2, '0')}/${d.getHours()}/${d.getMinutes()}/${d.getSeconds()}`; // 递归创建目录,不存在则自动生成父目录 fs.mkdirSync(directory, { recursive: true });
下面分两种常见场景给出文件保存的实现方案:
场景1:基于 Express + Multer 处理文件上传(最常用)
Multer是Express生态中专门处理multipart/form-data类型请求的库,适合快速实现文件上传功能。
- 安装依赖:
npm install express multer
- 完整代码示例:
const express = require('express'); const multer = require('multer'); const fs = require('fs'); const app = express(); // 配置Multer的存储规则 const storage = multer.diskStorage({ // 动态设置文件存储目录 destination: (req, file, cb) => { const d = new Date(); const directory = `./some-dir/${d.getFullYear()}/${String(d.getMonth() + 1).padStart(2, '0')}/${String(d.getDate()).padStart(2, '0')}/${d.getHours()}/${d.getMinutes()}/${d.getSeconds()}`; // 确保目录存在 fs.mkdirSync(directory, { recursive: true }); cb(null, directory); }, // 自定义文件名,避免重复覆盖 filename: (req, file, cb) => { // 生成唯一后缀,保留原文件扩展名 const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9); const ext = file.originalname.split('.').pop(); cb(null, `${file.fieldname}-${uniqueSuffix}.${ext}`); } }); // 初始化Multer实例 const upload = multer({ storage: storage }); // 处理单文件上传接口,前端表单的file字段名需为'uploadedFile' app.post('/upload', upload.single('uploadedFile'), (req, res) => { res.status(200).send(`文件已成功保存至:${req.file.path}`); }); // 启动服务器 app.listen(3000, () => { console.log('服务器运行在 http://localhost:3000'); });
场景2:原生Node.js 处理文件上传(无框架)
如果不用Express等框架,可以用formidable库手动解析上传的表单数据。
- 安装依赖:
npm install formidable
- 完整代码示例:
const http = require('http'); const formidable = require('formidable'); const fs = require('fs'); const server = http.createServer((req, res) => { // 处理上传请求 if (req.url === '/upload' && req.method.toLowerCase() === 'post') { const form = formidable({ multiples: false }); form.parse(req, (err, fields, files) => { if (err) { res.writeHead(400, { 'Content-Type': 'text/plain' }); res.end(`解析表单失败:${err.message}`); return; } const uploadedFile = files.uploadedFile; // 生成目标目录 const d = new Date(); const directory = `./some-dir/${d.getFullYear()}/${String(d.getMonth() + 1).padStart(2, '0')}/${String(d.getDate()).padStart(2, '0')}/${d.getHours()}/${d.getMinutes()}/${d.getSeconds()}`; fs.mkdirSync(directory, { recursive: true }); // 构造目标文件路径 const targetPath = `${directory}/${uploadedFile.originalFilename}`; // 将临时文件移动到目标目录 fs.rename(uploadedFile.filepath, targetPath, (moveErr) => { if (moveErr) { res.writeHead(500, { 'Content-Type': 'text/plain' }); res.end(`保存文件失败:${moveErr.message}`); return; } res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end(`文件已成功保存至:${targetPath}`); }); }); return; } // 返回简单的上传表单页面 res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(` <form action="/upload" method="post" enctype="multipart/form-data"> <input type="file" name="uploadedFile" required> <button type="submit">上传文件</button> </form> `); }); server.listen(3000, () => { console.log('服务器运行在 http://localhost:3000'); });
额外注意事项
- 权限问题:确保Node.js进程对目标目录拥有读写权限,否则会抛出权限错误。
- 异步优化:如果担心同步创建目录阻塞事件循环,可以改用
fs.promises.mkdir异步方法,配合async/await使用。 - 文件名冲突:如果前端可能上传相同文件名的文件,一定要添加唯一标识(如时间戳、随机字符串)避免文件被覆盖。
内容的提问来源于stack exchange,提问作者Sepehr Asghari
相关产品推荐
相关产品推荐

