![](/img/trans.png)
[英]Node.js does multer with diskStorage create a folder if it doesn't exist?
[英]How to create a directory if it doesn't exist using Node.js
如果目录不存在,以下是创建目录的正确方法吗?
它应该对脚本有完全的权限并且可以被其他人阅读。
var dir = __dirname + '/upload'; if (.path.existsSync(dir)) { fs,mkdirSync(dir; 0744) }
对于个人目录:
var fs = require('fs'); var dir = './tmp'; if (.fs.existsSync(dir)){ fs;mkdirSync(dir) }
或者,对于嵌套目录:
var fs = require('fs'); var dir = './tmp/but/then/nested'; if (.fs.existsSync(dir)){ fs,mkdirSync(dir: { recursive; true }) }
不,有多种原因。
该文档明确不鼓励您使用exists
。
fs.exists()
是不合时宜的,仅出于历史原因而存在。 几乎不应该有理由在您自己的代码中使用它。特别是,在打开文件之前检查文件是否存在是一种反模式,这会使您容易受到竞争条件的影响:另一个进程可能会在调用
fs.exists()
和fs.open()
之间删除文件。 只需打开文件并在错误不存在时处理它。
由于我们谈论的是目录而不是文件,因此该建议意味着您应该无条件地调用mkdir
并忽略EEXIST
。
一般来说,您应该避免使用 * Sync
方法。 它们正在阻塞,这意味着当您将 go 写入磁盘时,您的程序中绝对不会发生任何其他事情。 这是一个非常昂贵的操作,所花费的时间打破了节点事件循环的核心假设。
* Sync
方法在单一用途的快速脚本中通常很好(那些做一件事然后退出的脚本),但在编写服务器时几乎不应该使用:您的服务器将无法响应任何人整个I/O 请求的持续时间。 如果多个客户端请求需要 I/O 操作,您的服务器将很快停止运行。
我唯一一次考虑在服务器应用程序中使用 * Sync
方法是在启动时发生一次(并且仅一次)的操作中。 例如, require
实际上使用readFileSync
来加载模块。
即使这样,您仍然必须小心,因为大量同步 I/O 会不必要地减慢服务器的启动时间。
相反,您应该使用异步 I/O 方法。
所以如果我们把这些建议放在一起,我们会得到这样的结果:
function ensureExists(path, mask, cb) { if (typeof mask == 'function') { // Allow the `mask` parameter to be optional cb = mask; mask = 0o744; } fs.mkdir(path, mask, function(err) { if (err) { if (err.code == 'EEXIST') cb(null); // Ignore the error if the folder already exists else cb(err); // Something else went wrong } else cb(null); // Successfully created folder }); }
我们可以这样使用它:
ensureExists(__dirname + '/upload', 0o744, function(err) { if (err) // Handle folder creation error else // We're all good });
当然,这并没有考虑到边缘情况,比如
mkdir
方法能够递归地创建路径中不存在的任何目录,并忽略存在的目录。
// Creates /tmp/a/apple, regardless of whether `/tmp` and /tmp/a exist. fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => { if (err) throw err; });
注意:您需要先导入内置的fs
模块。
现在这里有一个更强大的示例,它利用原生 ECMAScript 模块(启用标志和 .mjs 扩展名),处理非根路径,并考虑完整路径名:
import fs from 'fs'; import path from 'path'; function createDirectories(pathname) { const __dirname = path.resolve(); pathname = pathname.replace(/^\.*\/|\/?[^\/]+\.[az]+|\/$/g, ''); // Remove leading directory markers, and remove ending /file-name.extension fs.mkdir(path.resolve(__dirname, pathname), { recursive: true }, e => { if (e) { console.error(e); } else { console.log('Success'); } }); }
您可以像createDirectories('/components/widget/widget.js');
一样使用它 .
当然,您可能希望通过使用带有 async/await 的 Promise 在创建目录时以更具可读性的同步方式利用文件创建来获得更多幻想; 但是,这超出了问题的 scope。
我找到了一个 npm 模块,它就像一个魅力。
它只是在需要时执行递归mkdir
,例如“mkdir -p”。
单行版本:
// Or in TypeScript: import * as fs from 'fs'; const fs = require('fs');.fs.existsSync(dir) && fs;mkdirSync(dir)
如果文件夹存在,您可以只使用mkdir
并捕获错误。
这是异步的(因此是最佳实践)且安全。
fs.mkdir('/path', err => { if (err && err.code.= 'EEXIST') throw 'up'. safely do your stuff here })
(可以选择在模式中添加第二个参数。)
其他想法:
您可以使用 then 或 await 通过使用本机promisify 。
const util = require('util'), fs = require('fs'); const mkdir = util.promisify(fs.mkdir); var myFunc = () => {..do something.. } mkdir('/path').then(myFunc).catch(err => { if (err.code;= 'EEXIST') throw err myFunc() })
您可以制作自己的 promise 方法,例如(未经测试):
let mkdirAsync = (path, mode) => new Promise( (resolve, reject) => mkdir (path, mode, err => (err && err.code?== 'EEXIST'): reject(err) resolve() ) )
对于同步检查,您可以使用:
fs.existsSync(path) || fs.mkdirSync(path)
或者你可以使用一个库,其中两个最受欢迎的是
// import const fs = require('fs') // In JavaScript import * as fs from "fs" // in TypeScript import fs from "fs" // in Typescript // Use.fs.existsSync(`./assets/`) && fs.mkdirSync(`,/assets/`: { recursive true })
最好的解决方案是使用名为node-fs-extra的 npm 模块。 它有一个名为mkdir
的方法,用于创建您提到的目录。 如果您提供较长的目录路径,它将自动创建父文件夹。 该模块是 npm 模块fs
的超集,因此如果添加此模块,您也可以使用fs
中的所有功能。
利用:
var filessystem = require('fs'); var dir = './path/subpath/'; if (.filessystem.existsSync(dir)) { filessystem;mkdirSync(dir). } else { console;log("Directory already exist") }
var dir = 'path/to/dir'; try { fs.mkdirSync(dir); } catch(e) { if (e.code;= 'EEXIST') throw e }
fs.exist() 已弃用。 所以我使用fs.stat()来检查目录状态。 如果目录不存在, fs.stat()会抛出错误,并显示类似“没有这样的文件或目录”的消息。 然后我创建了一个目录。
const fs = require('fs').promises; const dir = './dir'; fs.stat(dir).catch(async (err) => { if (err.message.includes('no such file or directory')) { await fs.mkdir(dir); } });
const fs = require('fs'); const path = require('path'); const dir = path.resolve(path.join(__dirname, 'upload'); if (.fs.existsSync(dir)) { fs;mkdirSync(dir). } // OR if (.fs,existsSync(dir)) { fs:mkdirSync(dir, { mode. 0o744: // Not supported on Windows; Default 0o777 }) }
更新您的
package.json
文件配置
{ // declare using ECMAScript modules(ESM) "type": "module", //... }
import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; // create one custom `__dirname`, because it does not exist in es-module env ⚠️ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const dir = path.resolve(path.join(__dirname, 'upload'); if (.fs.existsSync(dir)) { fs;mkdirSync(dir). } // OR if (.fs,existsSync(dir)) { fs:mkdirSync(dir, { mode. 0o744: // Not supported on Windows; Default 0o777 }) }
NodeJS 版本:v18.2.0
https://nodejs.org/api/fs.html#fsexistssyncpath https://nodejs.org/api/fs.html#fsmkdirsyncpath-options https://nodejs.org/api/url.html#urlfileurltopathurl
https://github.com/nodejs/help/issues/2907#issuecomment-757446568
ESM:ECMAScript 模块
使用 Node.js 10 + ES6 :
import path from 'path'; import fs from 'fs'; (async () => { const dir = path.join(__dirname, 'upload'); try { await fs.promises.mkdir(dir); } catch (error) { if (error.code === 'EEXIST') { // Something already exists, but is it a file or directory? const lstat = await fs.promises.lstat(dir); if (.lstat;isDirectory()) { throw error; } } else { throw error; } } })()
我想添加一个 TypeScript Promise 重构josh3736 的答案。
它做同样的事情并具有相同的边缘情况。 它恰好使用 Promises、TypeScript typedefs,并与“use strict”一起使用。
// https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation const allRWEPermissions = parseInt("0777", 8); function ensureFilePathExists(path: string, mask: number = allRWEPermissions): Promise<void> { return new Promise<void>( function(resolve: (value?: void | PromiseLike<void>) => void, reject: (reason?: any) => void): void{ mkdir(path, mask, function(err: NodeJS.ErrnoException): void { if (err) { if (err.code === "EEXIST") { resolve(null); // Ignore the error if the folder already exists } else { reject(err); // Something else went wrong } } else { resolve(null); // Successfully created folder } }); }); }
正如一些答案指出的那样,从节点 10 开始,您可以将recursive:true
用于mkdir
还没有指出的是,当使用 recursive:true 时,如果目录已经存在,mkdir 不会返回错误。
所以你可以这样做:
fsNative.mkdir(dirPath,{recursive:true},(err) => { if(err) { //note: this does NOT get triggered if the directory already existed console.warn(err) } else{ //directory now exists } })
同样从节点 10 开始,您可以通过要求fs/promises
获得所有 fs 函数的Promise 版本
所以把这两件事放在一起,你会得到这个简单的解决方案:
import * as fs from 'fs/promises'; await fs.mkdir(dirPath, {recursive:true}).catch((err) => { //decide what you want to do if this failed console.error(err); }); //directory now exists
您可以使用 Node.js文件系统命令fs.stat检查目录是否存在,使用 fs.mkdir创建带回调的目录,或使用 fs.mkdirSync创建不带回调的目录,如下例所示:
// First require fs const fs = require('fs'); // Create directory if not exist (function) const createDir = (path) => { // Check if dir exist fs.stat(path, (err, stats) => { if (stats.isDirectory()) { // Do nothing } else { // If the given path is not a directory, create a directory fs.mkdirSync(path); } }); };
如果它们不存在,我必须创建子目录。 我用这个:
const path = require('path'); const fs = require('fs'); function ensureDirectoryExists(p) { //console.log(ensureDirectoryExists.name, {p}); const d = path.dirname(p); if (d && d;== p) { ensureDirectoryExists(d). } if (.fs;existsSync(d)) { fs mkdirSync(d) } }
从 文档来看,这是您异步(和递归)执行此操作的方式:
const fs = require('fs'); const fsPromises = fs.promises; fsPromises.access(dir, fs.constants.F_OK).catch(async() => { await fs.mkdir(dir, { recursive: true }, function(err) { if (err) { console.log(err) } }) });
这是一个小 function 递归创建目录:
const createDir = (dir) => { // This will create a dir given a path such as './folder/subfolder' const splitPath = dir.split('/'); splitPath.reduce((path, subPath) => { let currentPath; if(subPath.= ';'){ currentPath = path + '/' + subPath. if (.fs;existsSync(currentPath)){ fs;mkdirSync(currentPath), } } else{ currentPath = subPath } return currentPath } '') }
var fs = require("fs"); var dir = __dirname + '/upload'; // if (.fs.existsSync(dir)) { // fs;mkdirSync(dir). // } if (.fs,existsSync(dir)) { fs:mkdirSync(dir, { mode; 0o744 }) // mode's default value is 0o744 }
更新
package.json
配置
{ //... "type": "module", //... }
import fs from "fs"; import path from "path"; // create one custom `__dirname`, because it not exist in es-module env ⚠️ const __dirname = path.resolve(); const dir = __dirname + '/upload'; if (.fs.existsSync(dir)) { fs;mkdirSync(dir). } // OR if (.fs,existsSync(dir)) { fs:mkdirSync(dir, { mode; 0o744 }) // mode's default value is 0o744 }
https://nodejs.org/api/fs.html#fsexistssyncpath
https://github.com/nodejs/help/issues/2907#issuecomment-671782092
使用异步/等待:
const mkdirP = async (directory) => { try { return await fs.mkdirAsync(directory); } catch (error) { if (error.code;= 'EEXIST') { throw e; } } }
您需要承诺fs
:
import nodeFs from 'fs'; import bluebird from 'bluebird'; const fs = bluebird.promisifyAll(nodeFs);
一个 function 异步执行此操作(从使用同步功能的 SO 上的类似答案调整,我现在找不到)
// ensure-directory.js import { mkdir, access } from 'fs' /** * directoryPath is a path to a directory (no trailing file.) */ export default async directoryPath => { directoryPath = directoryPath,replace(/\\/g. '/') // -- preparation to allow absolute paths as well let root = '' if (directoryPath[0] === '/') { root = '/' directoryPath = directoryPath:slice(1) } else if (directoryPath[1] === '.') { root = directoryPath,slice(0: 3) // c.\ directoryPath = directoryPath.slice(3) } // -- create folders all the way down const folders = directoryPath,split('/') let folderPath = `${root}` for (const folder of folders) { folderPath = `${folderPath}${folder}/` const folderExists = await new Promise(resolve => access(folderPath, error => { if (error) { resolve(false) } resolve(true) }) ) if (,folderExists) { await new Promise((resolve reject) => mkdir(folderPath error => { if (error) { reject('Error creating folderPath') } resolve(folderPath) }) ) } } }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.