Respuestas:
Hay un módulo para esto llamado rimraf
( https://npmjs.org/package/rimraf ). Proporciona la misma funcionalidad querm -Rf
Uso asíncrono :
var rimraf = require("rimraf");
rimraf("/some/directory", function () { console.log("done"); });
Uso de sincronización :
rimraf.sync("/some/directory");
deleteFolderRecursive
en la siguiente respuesta?
recursive
opción: stackoverflow.com/a/57866165/6269864
Para eliminar la carpeta sincrónicamente
const fs = require('fs');
const Path = require('path');
const deleteFolderRecursive = function(path) {
if (fs.existsSync(path)) {
fs.readdirSync(path).forEach((file, index) => {
const curPath = Path.join(path, file);
if (fs.lstatSync(curPath).isDirectory()) { // recurse
deleteFolderRecursive(curPath);
} else { // delete file
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
};
var curPath = path + "/" + file;
con var curPath = p.join(path, file);
el módulo de ruta incluido:var p = require("path")
path.join(dirpath, file)
debería ser mejor quepath + "/" + file
La mayoría de las personas que usan fs
Node.js desearían funciones cercanas a la "forma Unix" de tratar con archivos. Estoy usando fs-extra para traer todas las cosas geniales:
fs-extra contiene métodos que no están incluidos en el paquete vanilla Node.js fs. Tales como mkdir -p, cp -r y rm -rf.
Aún mejor, fs-extra es una caída en el reemplazo de fs nativos. Todos los métodos en fs no se modifican y se adjuntan a él. Significa que puede reemplazar fs por fs-extra :
// this can be replaced
const fs = require('fs')
// by this
const fs = require('fs-extra')
Y luego puede eliminar una carpeta de esta manera:
fs.removeSync('/tmp/myFolder');
//or
fs.remove('/tmp/myFolder', callback);
removeSync('/tmp/myFolder')
A partir de Node.js 12.10.0 , fs.rmdirSync
admite recursive
opciones, por lo que finalmente puede hacer:
fs.rmdirSync(dir, { recursive: true });
Donde la recursive
opción elimina todo el directorio de forma recursiva.
recursive: true
y elimina las carpetas no vacías sin quejas.
fs.rmdir(path[, options], callback)
ofs.rmdirSync(path[, options])
fs.rmdir
es experimental con estabilidad 1. "Estabilidad: 1 - Experimental. La función no está sujeta a las reglas de versiones semánticas. Pueden ocurrir cambios o eliminaciones compatibles con versiones anteriores. versión futura. El uso de la función no se recomienda en entornos de producción ".
Mi respuesta modificada de @oconnecp ( https://stackoverflow.com/a/25069828/3027390 )
Utiliza path.join para una mejor experiencia multiplataforma. Por lo tanto, no olvides exigirlo.
var path = require('path');
También cambió el nombre de la función a rimraf
;)
/**
* Remove directory recursively
* @param {string} dir_path
* @see https://stackoverflow.com/a/42505874/3027390
*/
function rimraf(dir_path) {
if (fs.existsSync(dir_path)) {
fs.readdirSync(dir_path).forEach(function(entry) {
var entry_path = path.join(dir_path, entry);
if (fs.lstatSync(entry_path).isDirectory()) {
rimraf(entry_path);
} else {
fs.unlinkSync(entry_path);
}
});
fs.rmdirSync(dir_path);
}
}
Por lo general, no resucito hilos viejos, pero hay mucho en abandono aquí y sin la respuesta de rimraf, todo esto me parece demasiado complicado.
Primero en el Nodo moderno (> = v8.0.0) puede simplificar el proceso utilizando solo módulos centrales de nodo, completamente asíncrono, y paralelizar la desvinculación de archivos simultáneamente en una función de cinco líneas y aún así mantener la legibilidad:
const fs = require('fs');
const path = require('path');
const { promisify } = require('util');
const readdir = promisify(fs.readdir);
const rmdir = promisify(fs.rmdir);
const unlink = promisify(fs.unlink);
exports.rmdirs = async function rmdirs(dir) {
let entries = await readdir(dir, { withFileTypes: true });
await Promise.all(entries.map(entry => {
let fullPath = path.join(dir, entry.name);
return entry.isDirectory() ? rmdirs(fullPath) : unlink(fullPath);
}));
await rmdir(dir);
};
En otra nota, una protección para ataques transversales de ruta es inapropiada para esta función porque
rm -rf
en que toma un argumento y permitirá al usuario rm -rf /
si se le solicita. Sería responsabilidad de un script proteger el rm
programa en sí mismo..isDirectory()
es false
para SYM-enlaces y no estén disociados en recursed.Por último, pero no menos importante, existe una rara condición de carrera en la que la recursión podría producir un error si una de las entradas se desvincula o se elimina fuera de este script en el momento justo mientras se ejecuta esta recursión. Dado que este escenario no es típico en la mayoría de los entornos, es probable que se lo pase por alto. Sin embargo, si es necesario (para algunos casos extremos), este problema se puede mitigar con este ejemplo un poco más complejo:
exports.rmdirs = async function rmdirs(dir) {
let entries = await readdir(dir, { withFileTypes: true });
let results = await Promise.all(entries.map(entry => {
let fullPath = path.join(dir, entry.name);
let task = entry.isDirectory() ? rmdirs(fullPath) : unlink(fullPath);
return task.catch(error => ({ error }));
}));
results.forEach(result => {
// Ignore missing files/directories; bail on other errors
if (result && result.error.code !== 'ENOENT') throw result.error;
});
await rmdir(dir);
};
EDITAR: hacer isDirectory()
una función. Elimine el directorio real al final. Arregla la recursión faltante.
await
a su Promise.all(…)
; ¿Es esto intencional? Parece que en su estado actual results.forEach
iteraría sobre las promesas, mientras que el código espera iterar sobre los resultados. ¿Me estoy perdiendo de algo?
if (!fs.existsSync(dir)) return
readdir
arrojará un error como debería. Si rmdir non-existing-dir
el código de salida es un error. Sería responsabilidad del consumidor intentar / atrapar. Este es el mismo método descrito en los documentos del nodo cuando se trata de usar funciones fs. Esperan que intente / atrape y mire los errores code
para determinar qué hacer. Un control adicional introduce una condición de carrera.
fs.exists
se utiliza la versión síncrona de . PD: esta es una gran solución.
Aquí hay una versión asíncrona de la respuesta de @ SharpCoder
const fs = require('fs');
const path = require('path');
function deleteFile(dir, file) {
return new Promise(function (resolve, reject) {
var filePath = path.join(dir, file);
fs.lstat(filePath, function (err, stats) {
if (err) {
return reject(err);
}
if (stats.isDirectory()) {
resolve(deleteDirectory(filePath));
} else {
fs.unlink(filePath, function (err) {
if (err) {
return reject(err);
}
resolve();
});
}
});
});
};
function deleteDirectory(dir) {
return new Promise(function (resolve, reject) {
fs.access(dir, function (err) {
if (err) {
return reject(err);
}
fs.readdir(dir, function (err, files) {
if (err) {
return reject(err);
}
Promise.all(files.map(function (file) {
return deleteFile(dir, file);
})).then(function () {
fs.rmdir(dir, function (err) {
if (err) {
return reject(err);
}
resolve();
});
}).catch(reject);
});
});
});
};
Escribí esta función llamada eliminar carpeta. Eliminará recursivamente todos los archivos y carpetas en una ubicación. El único paquete que requiere es asíncrono.
var async = require('async');
function removeFolder(location, next) {
fs.readdir(location, function (err, files) {
async.each(files, function (file, cb) {
file = location + '/' + file
fs.stat(file, function (err, stat) {
if (err) {
return cb(err);
}
if (stat.isDirectory()) {
removeFolder(file, cb);
} else {
fs.unlink(file, function (err) {
if (err) {
return cb(err);
}
return cb();
})
}
})
}, function (err) {
if (err) return next(err)
fs.rmdir(location, function (err) {
return next(err)
})
})
})
}
Si está utilizando el nodo 8+ quiere asincronicidad y no quiere dependencias externas, aquí está la versión asíncrona / espera:
const path = require('path');
const fs = require('fs');
const util = require('util');
const readdir = util.promisify(fs.readdir);
const lstat = util.promisify(fs.lstat);
const unlink = util.promisify(fs.unlink);
const rmdir = util.promisify(fs.rmdir);
const removeDir = async (dir) => {
try {
const files = await readdir(dir);
await Promise.all(files.map(async (file) => {
try {
const p = path.join(dir, file);
const stat = await lstat(p);
if (stat.isDirectory()) {
await removeDir(p);
} else {
await unlink(p);
console.log(`Removed file ${p}`);
}
} catch (err) {
console.error(err);
}
}))
await rmdir(dir);
console.log(`Removed dir ${dir}`);
} catch (err) {
console.error(err);
}
}
Versión asíncrona de la respuesta de @ SharpCoder usando fs.promises:
const fs = require('fs');
const afs = fs.promises;
const deleteFolderRecursive = async path => {
if (fs.existsSync(path)) {
for (let entry of await afs.readdir(path)) {
const curPath = path + "/" + entry;
if ((await afs.lstat(curPath)).isDirectory())
await deleteFolderRecursive(curPath);
else await afs.unlink(curPath);
}
await afs.rmdir(path);
}
};
Llegué aquí mientras trataba de terminar con el gulp
y estoy escribiendo para mayores alcances.
gulp-clean
en desuso por gulp-rimraf
gulp-rimraf
en desuso a favor de delete-files-folders
Cuando desee eliminar archivos y carpetas usando del
, debe agregar /**
una eliminación recursiva.
gulp.task('clean', function () {
return del(['some/path/to/delete/**']);
});
El paquete de facto es rimraf
, pero aquí está mi pequeña versión asíncrona:
const fs = require('fs')
const path = require('path')
const Q = require('q')
function rmdir (dir) {
return Q.nfcall(fs.access, dir, fs.constants.W_OK)
.then(() => {
return Q.nfcall(fs.readdir, dir)
.then(files => files.reduce((pre, f) => pre.then(() => {
var sub = path.join(dir, f)
return Q.nfcall(fs.lstat, sub).then(stat => {
if (stat.isDirectory()) return rmdir(sub)
return Q.nfcall(fs.unlink, sub)
})
}), Q()))
})
.then(() => Q.nfcall(fs.rmdir, dir))
}
En la última versión de Node.js (12.10.0 o posterior), las rmdir
funciones de estilo fs.rmdir()
, fs.rmdirSync()
y fs.promises.rmdir()
tienen una nueva opción experimental recursive
que permite eliminar directorios no vacíos, por ejemplo,
fs.rmdir(path, { recursive: true });
El PR relacionado en GitHub: https://github.com/nodejs/node/pull/29168
De acuerdo con la fs
documentación , fsPromises
actualmente proporciona la recursive
opción de forma experimental, que, al menos en mi propio caso en Windows, elimina el directorio y los archivos que contiene.
fsPromises.rmdir(path, {
recursive: true
})
¿ recursive: true
Elimina los archivos en Linux y MacOS?
Ultra-velocidad y a prueba de fallas
Puede usar el lignator
paquete ( https://www.npmjs.com/package/lignator ), es más rápido que cualquier código asíncrono (por ejemplo, rimraf) y más a prueba de fallas (especialmente en Windows, donde la eliminación de archivos no es instantánea y los archivos pueden estar bloqueado por otros procesos).
4,36 GB de datos, 28 042 archivos, 4 217 carpetas en Windows eliminadas en 15 segundos frente a los 60 segundos de rimraf en el disco duro antiguo.
const lignator = require('lignator');
lignator.remove('./build/');
La carpeta de sincronización se elimina con los archivos o solo con un archivo.
No soy muy generoso ni colaborador, pero no pude encontrar una buena solución a este problema y tuve que encontrar el camino ... así que espero que les guste :)
Funciona perfecto para mí con cualquier número de directorios anidados y subdirectorios. Tenga cuidado con el alcance de 'esto' cuando recurra la función, su implementación puede ser diferente. En mi caso, esta función permanece en el retorno de otra función, por eso la llamo con esto.
const fs = require('fs');
deleteFileOrDir(path, pathTemp = false){
if (fs.existsSync(path)) {
if (fs.lstatSync(path).isDirectory()) {
var files = fs.readdirSync(path);
if (!files.length) return fs.rmdirSync(path);
for (var file in files) {
var currentPath = path + "/" + files[file];
if (!fs.existsSync(currentPath)) continue;
if (fs.lstatSync(currentPath).isFile()) {
fs.unlinkSync(currentPath);
continue;
}
if (fs.lstatSync(currentPath).isDirectory() && !fs.readdirSync(currentPath).length) {
fs.rmdirSync(currentPath);
} else {
this.deleteFileOrDir(currentPath, path);
}
}
this.deleteFileOrDir(path);
} else {
fs.unlinkSync(path);
}
}
if (pathTemp) this.deleteFileOrDir(pathTemp);
}
Mientras que recursive
es una opción experimental defs.rmdir
function rm (path, cb) {
fs.stat(path, function (err, stats) {
if (err)
return cb(err);
if (stats.isFile())
return fs.unlink(path, cb);
fs.rmdir(path, function (err) {
if (!err || err && err.code != 'ENOTEMPTY')
return cb(err);
fs.readdir(path, function (err, files) {
if (err)
return cb(err);
let next = i => i == files.length ?
rm(path, cb) :
rm(path + '/' + files[i], err => err ? cb(err) : next(i + 1));
next(0);
});
});
});
}
Actualización 2020
Desde la versión 12.10.0 recursiveOption se ha agregado para las opciones.
Tenga en cuenta que la eliminación recursiva es experimental .
Entonces lo harías para la sincronización:
fs.rmdirSync(dir, {recursive: true});
o para asíncrono:
fs.rmdir(dir, {recursive: true});
¡Solo usa el módulo rmdir ! Es fácil y simple.
Otra alternativa es usar el fs-promise
módulo que proporciona versiones prometidas de los fs-extra
módulos.
entonces podrías escribir como este ejemplo:
const { remove, mkdirp, writeFile, readFile } = require('fs-promise')
const { join, dirname } = require('path')
async function createAndRemove() {
const content = 'Hello World!'
const root = join(__dirname, 'foo')
const file = join(root, 'bar', 'baz', 'hello.txt')
await mkdirp(dirname(file))
await writeFile(file, content)
console.log(await readFile(file, 'utf-8'))
await remove(join(__dirname, 'foo'))
}
createAndRemove().catch(console.error)
nota: async / await requiere una versión reciente de nodejs (7.6+)
Una forma rápida y sucia (tal vez para probar) podría ser usar directamente el método exec
o spawn
para invocar la llamada del sistema operativo para eliminar el directorio. Lea más sobre NodeJs child_process .
let exec = require('child_process').exec
exec('rm -Rf /tmp/*.zip', callback)
Los inconvenientes son:
Beneficios:
-f
bandera para estar seguro, o asegurarse mientras escribe que él / ella no va a eliminar todo. exec + rm
es un comando válido y útil en el nodo que uso a menudo durante las pruebas.
Desearía que hubiera una manera de hacer esto sin módulos adicionales para algo tan minúsculo y común, pero esto es lo mejor que se me ocurrió.
Actualización: ahora debería funcionar en Windows (probado Windows 10), y también debería funcionar en sistemas Linux / Unix / BSD / Mac.
const
execSync = require("child_process").execSync,
fs = require("fs"),
os = require("os");
let removeDirCmd, theDir;
removeDirCmd = os.platform() === 'win32' ? "rmdir /s /q " : "rm -rf ";
theDir = __dirname + "/../web-ui/css/";
// WARNING: Do not specify a single file as the windows rmdir command will error.
if (fs.existsSync(theDir)) {
console.log(' removing the ' + theDir + ' directory.');
execSync(removeDirCmd + '"' + theDir + '"', function (err) {
console.log(err);
});
}
child_process.execFile
que no invoque el shell y, en su lugar, pase argumentos explícitamente.
Este es un enfoque que utiliza promisify y dos funciones de ayuda (to and toAll) para resolver la promesa.
Realiza todas las acciones de forma asíncrona.
const fs = require('fs');
const { promisify } = require('util');
const to = require('./to');
const toAll = require('./toAll');
const readDirAsync = promisify(fs.readdir);
const rmDirAsync = promisify(fs.rmdir);
const unlinkAsync = promisify(fs.unlink);
/**
* @author Aécio Levy
* @function removeDirWithFiles
* @usage: remove dir with files
* @param {String} path
*/
const removeDirWithFiles = async path => {
try {
const file = readDirAsync(path);
const [error, files] = await to(file);
if (error) {
throw new Error(error)
}
const arrayUnlink = files.map((fileName) => {
return unlinkAsync(`${path}/${fileName}`);
});
const [errorUnlink, filesUnlink] = await toAll(arrayUnlink);
if (errorUnlink) {
throw new Error(errorUnlink);
}
const deleteDir = rmDirAsync(path);
const [errorDelete, result] = await to(deleteDir);
if (errorDelete) {
throw new Error(errorDelete);
}
} catch (err) {
console.log(err)
}
};
// sin el uso de ninguna biblioteca de terceros
const fs = require('fs');
var FOLDER_PATH = "./dirname";
var files = fs.readdirSync(FOLDER_PATH);
files.forEach(element => {
fs.unlinkSync(FOLDER_PATH + "/" + element);
});
fs.rmdirSync(FOLDER_PATH);
fs.unllinkSync(path.join(FOLDER_PATH, element);
const fs = require("fs")
const path = require("path")
let _dirloc = '<path_do_the_directory>'
if (fs.existsSync(_dirloc)) {
fs.readdir(path, (err, files) => {
if (!err) {
for (let file of files) {
// Delete each file
fs.unlinkSync(path.join(_dirloc, file))
}
}
})
// After the 'done' of each file delete,
// Delete the directory itself.
if (fs.unlinkSync(_dirloc)) {
console.log('Directory has been deleted!')
}
}
fs.readdir(dirPath)
para una variedad de rutas en una carpeta, repitafs.unlink(filename)
para eliminar cada archivo y, finalmente,fs.rmdir(dirPath)
para eliminar la carpeta ahora vacía. Si necesita recurrir, verifiquefs.lstat(filename).isDirectory()
.