node.js - ¿Nodo cómo crear un directorio si no existe?
(11)
Aquí hay una pequeña función para crear directorios de forma recursiva:
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
}, '''')
}
¿Es esta la forma correcta de crear un directorio si no existe? Debe tener permiso completo para el script y legible por otros.
var dir = __dirname + ''/upload'';
if (!path.existsSync(dir)) {
fs.mkdirSync(dir, 0744);
}
He encontrado un módulo npm que funciona como un encanto para esto. Es simplemente hacer un mkdir recursivamente cuando sea necesario, como un "mkdir -p".
La mejor solución sería usar el módulo npm llamado github.com/jprichardson/node-fs-extra . Tiene un método llamado mkdir
que crea el directorio que mencionaste. Si da una ruta de directorio larga, creará las carpetas principales automáticamente. El módulo es un super conjunto de npm module fs
, por lo que puede usar todas las funciones en fs
también si agrega este módulo.
Me gustaría agregar un refactor de Typescript Promise de la respuesta de josh3736 .
Hace lo mismo y tiene los mismos casos de borde, simplemente pasa a usar Promesas, typedefs mecanografiado y trabaja con "uso estricto".
// 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
}
});
});
}
No, por múltiples razones.
El módulo de
path
no tiene un métodoexists
/existsSync
. Está en el módulofs
. (Tal vez usted acaba de hacer un error tipográfico en su pregunta?)fs uso de la
exists
.fs.exists()
es un anacronismo y existe solo por razones históricas. Casi nunca debería haber una razón para usarlo en su propio código.En particular, verificar si existe un archivo antes de abrirlo es un antipatrón que lo deja vulnerable a las condiciones de carrera: otro proceso puede eliminar el archivo entre las llamadas a
fs.exists()
yfs.open()
. Solo abre el archivo y maneja el error cuando no esté allí.Ya que estamos hablando de un directorio en lugar de un archivo, este consejo implica que debe llamar incondicionalmente a
mkdir
e ignorarEEXIST
.En general, debes evitar los * métodos de
Sync
. Están bloqueando, lo que significa que no puede pasar absolutamente nada más en su programa mientras usted va al disco. Esta es una operación muy costosa, y el tiempo que toma rompe la suposición central del bucle de eventos del nodo.Los * métodos de
Sync
generalmente están bien en los scripts rápidos de un solo propósito (aquellos que hacen una cosa y luego se cierran), pero casi nunca deben usarse cuando está escribiendo un servidor: su servidor no podrá responder a nadie por completo Duración de las solicitudes de E / S. Si varias solicitudes de clientes requieren operaciones de E / S, su servidor se detendrá rápidamente.La única vez que consideraría usar * Métodos de
Sync
en una aplicación de servidor es en una operación que ocurre una vez (y solo una vez), al inicio. Por ejemplo,require
realmente usareadFileSync
para cargar módulos.Incluso entonces, debe tener cuidado porque muchas E / S síncronas pueden ralentizar innecesariamente el tiempo de inicio de su servidor.
En su lugar, debe utilizar los métodos de E / S asíncronos.
Entonces, si juntamos esos consejos, obtenemos algo como esto:
function ensureExists(path, mask, cb) {
if (typeof mask == ''function'') { // allow the `mask` parameter to be optional
cb = mask;
mask = 0777;
}
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
});
}
Y podemos usarlo así:
ensureExists(__dirname + ''/upload'', 0744, function(err) {
if (err) // handle folder creation error
else // we''re all good
});
Por supuesto, esto no tiene en cuenta los casos de borde como
- ¿Qué sucede si la carpeta se borra mientras se ejecuta el programa? (asumiendo que solo verifique que existe una vez durante el inicio)
- ¿Qué sucede si la carpeta ya existe pero con los permisos incorrectos?
Por si acaso alguien interesado en la versión de una línea. :)
//or in typescript: import * as fs from ''fs'';
const fs = require(''fs'');
!fs.existsSync(dir) && fs.mkdirSync(dir);
Solo puede usar mkdir
y detectar el error si la carpeta existe.
Esto es asíncrono (así que las mejores prácticas) y seguro.
fs.mkdir(''/path'', err => {
if (err && err.code != ''EEXIST'') throw ''up''
.. safely do your stuff here
})
(Opcionalmente agregue un segundo argumento con el modo.)
Otros pensamientos:
Usted podría usar entonces o esperar usando promisify nativo.
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() })
Puedes hacer tu propio método de promesa, algo como (sin probar):
let mkdirAsync = (path, mode) => new Promise( (resolve, reject) => mkdir (path, mode, err => (err && err.code !== ''EEXIST'') ? reject(err) : resolve() ) )
Para la comprobación síncrona, puede utilizar:
fs.existsSync(path) || fs.mkdirSync(path)
O puedes usar una biblioteca, las dos más populares son
Usando async / await:
const mkdirP = async (directory) => {
try {
return await fs.mkdirAsync(directory);
} catch (error) {
if (error.code != ''EEXIST'') {
throw e;
}
}
};
Necesitará promisificar fs
:
import nodeFs from ''fs'';
import bluebird from ''bluebird'';
const fs = bluebird.promisifyAll(nodeFs);
var filessystem = require(''fs'');
var dir = ''./path/subpath/'';
if (!filessystem.existsSync(dir)){
filessystem.mkdirSync(dir);
}else
{
console.log("Directory already exist");
}
Esto puede ayudarte :)
var dir = ''path/to/dir'';
try {
fs.mkdirSync(dir);
} catch(e) {
if (e.code ~= ''EEXIST'') throw e;
}
var fs = require(''fs'');
var dir = ''./tmp'';
if (!fs.existsSync(dir)){
fs.mkdirSync(dir);
}