it-swarm.com.de

Entfernen Sie ein Verzeichnis, das nicht leer ist

In meiner Knotenanwendung muss ich ein Verzeichnis entfernen, das einige Dateien enthält, aber fs.rmdir funktioniert nur bei leeren Verzeichnissen. Wie kann ich das machen?

186
sachin

Dafür gibt es ein Modul namens rimraf ( https://npmjs.org/package/rimraf ). Es bietet die gleiche Funktionalität wie rm -Rf

Async Verwendung:

var rimraf = require("rimraf");
rimraf("/some/directory", function () { console.log("done"); });

Sync Verwendung:

rimraf.sync("/some/directory");
202

Ordner synchron entfernen

var fs = require('fs');
var deleteFolderRecursive = function(path) {
  if (fs.existsSync(path)) {
    fs.readdirSync(path).forEach(function(file, index){
      var curPath = path + "/" + file;
      if (fs.lstatSync(curPath).isDirectory()) { // recurse
        deleteFolderRecursive(curPath);
      } else { // delete file
        fs.unlinkSync(curPath);
      }
    });
    fs.rmdirSync(path);
  }
};
141
SharpCoder

Die meisten Benutzer, die fs mit Node.js verwenden, möchten Funktionen, die der "Unix-Methode" im Umgang mit Dateien nahekommen. Ich benutze fs-extra , um all die coolen Sachen mitzubringen:

fs-extra enthält Methoden, die nicht in Vanilla Node.js .__ enthalten sind. fs paket. Wie mkdir -p, cp -r und rm -rf.

Noch besser: fs-extra ist ein Ersatz für native fs. Alle Methoden in fs sind nicht modifiziert und mit ihr verbunden. Sie können fs durch fs-extra ersetzen.

// this can be replaced
var fs = require('fs')

// by this
var fs = require('fs-extra')

Und dann können Sie einen Ordner folgendermaßen entfernen:

fs.removeSync('/tmp/myFolder'); 
//or
fs.remove('/tmp/myFolder', callback);
109
Pierre Maoui

Meine geänderte Antwort von @oconnecp ( https://stackoverflow.com/a/25069828/3027390 )

Verwendet path.join für bessere plattformübergreifende Benutzererfahrung ..__ Vergessen Sie nicht, es zu verlangen.

var path = require('path');

Funktion auch in rimraf umbenannt;)

/**
 * 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);
    }
}
16
thybzi

Hier ist eine asynchrone Version von @ SharpCoders Antwort

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);
            });
        });
    });
};
10
Tony Brix

Ich habe diese Funktion namens Ordner entfernen geschrieben. Es werden alle Dateien und Ordner an einem Ort rekursiv entfernt. Das einzige Paket, das es benötigt, ist asynchron.

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)
            })
        })
    })
}
9
oconnecp

Wenn Sie Knoten 8 oder höher verwenden, wollen Sie keine Synchronisierung und keine externen Abhängigkeiten, so ist hier die Async/Erwartungsversion:

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);
    }
}
6
RonZ

Ich habe hier versucht, mit der gulp fertig zu werden und schreibe für weitere Reichweite.

Wenn Sie Dateien und Ordner mit del löschen möchten, müssen Sie /** zum rekursiven Löschen anhängen.

gulp.task('clean', function () {
    return del(['some/path/to/delete/**']);
});
2
Jin Kwon

Normalerweise belebe ich alte Threads nicht wieder, aber es gibt ein loton churn here und sans the rimraf answer diese scheinen mir alle zu kompliziert zu sein.

Erstens können Sie in modernen Nodes (> = v8.0.0) den Vorgang vereinfachen, indem Sie nur Knoten-Core-Module verwenden, die vollständig asynchron sind, und das gleichzeitige Aufheben der Verknüpfung von Dateien in einer Funktion von fünf Zeilen parallelisieren und die Lesbarkeit beibehalten:

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 });
  return Promise.all(entries.map(entry => {
    let fullPath = path.join(dir, entry.name);
    return entry.isDirectory ? rmdir(fullPath) : unlink(fullPath);
  }));
};

Zum anderen ist eine Wache für Bahnüberquerungsangriffe für diese Funktion nicht geeignet, weil

  1. Es liegt außerhalb des Geltungsbereichs des Grundsatzes der einheitlichen Verantwortung .
  2. Sollte vom Aufrufer behandelt werden nichtthis-Funktion. Dies entspricht der Befehlszeile rm -rf, da sie ein Argument akzeptiert und es dem Benutzer ermöglicht, rm -rf / zu verwenden, wenn er dazu aufgefordert wird. Es liegt in der Verantwortung eines zu schützenden Skripts nicht das Programm rm selbst.
  3. Diese Funktion kann einen solchen Angriff nicht feststellen, da sie keinen Referenzrahmen hat. Auch dies liegt in der Verantwortung des Anrufers, der den Kontext der Absicht hat, der ihm eine Referenz zum Vergleichen der Pfaddurchquerung liefert.
  4. Sym-Links sind kein Problem, da .isDirectoryfalse für Sym-Links ist und nicht verlinkt und nicht rekursiv in.

Last but not least gibt es eine seltene Racebedingung, bei der die Rekursion fehlschlagen könnte, wenn einer der Einträge nicht verknüpft oder gelöscht wurde außerhalbdieses Skripts zum richtigen Zeitpunkt, während diese Rekursion ausgeführt wird. Da dieses Szenario in nicht typisch ist In den meisten Umgebungen kann dies wahrscheinlich übersehen werden. Bei Bedarf (in einigen Edge-Fällen) kann dieses Problem jedoch durch das folgende etwas komplexere Beispiel behoben werden:

exports.rmdirs = async function rmdirs(dir) {
  let entries = await readdir(dir, { withFileTypes: true });
  let results = Promise.all(entries.map(entry => {
    let fullPath = path.join(dir, entry.name);
    let task = entry.isDirectory ? rmdir(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;
  });
};
2
Sukima

Async-Version von @SharpCoder antwortet mit fs.promises:

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);
    }
};
1
Error404

Ein schneller und schmutziger Weg (vielleicht zum Testen) könnte die direkte Verwendung der Methode exec oder spawn sein, um den Aufruf des Betriebssystems zum Entfernen des Verzeichnisses aufzurufen. Weitere Informationen finden Sie unter NodeJs child_process .

let exec = require('child_process').exec
exec('rm -Rf /tmp/*.Zip', callback)

Nachteile sind:

  1. Sie sind abhängig vom zugrunde liegenden Betriebssystem, d. H. Die gleiche Methode würde unter Unix/Linux ausgeführt, aber wahrscheinlich nicht unter Windows.
  2. Sie können den Prozess nicht auf Bedingungen oder Fehler hijacken. Sie übergeben die Aufgabe einfach an das zugrunde liegende Betriebssystem und warten auf die Rückgabe des Exit-Codes.

Leistungen:

  1. Diese Prozesse können asynchron laufen.
  2. Sie können die Ausgabe/den Fehler des Befehls abhören, daher geht die Befehlsausgabe nicht verloren. Wenn der Vorgang nicht abgeschlossen ist, können Sie den Fehlercode überprüfen und es erneut versuchen.
1
Rash

Ordner synchronisieren mit den Dateien entfernen oder nur eine Datei.

Ich bin weder ein großer Geber noch ein Mitwirkender, aber ich konnte keine gute Lösung für dieses Problem finden und musste mich zurechtfinden ... also hoffe ich, dass es dir gefällt :)

Funktioniert perfekt mit einer beliebigen Anzahl von verschachtelten Verzeichnissen und Unterverzeichnissen. Achtung: Der Umfang von "this" kann bei der Rekursion der Funktion unterschiedlich sein. In meinem Fall bleibt diese Funktion in der Rückkehr einer anderen Funktion, deshalb rufe ich sie damit auf.

    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);
        }
1
q212

Verwenden Sie einfach rmdir module ! es ist einfach und einfach.

1
Aminovski

Promisifizierte Version:

const fs = require('fs')
const path = require('path')
const Q = require('q')

function rmdir(dir) {
  return Q.nfcall(fs.access, dir).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()))
  }, err => {})
  .then(() => Q.nfcall(fs.rmdir, dir))
}
1
Clark

Ich wünschte, es gäbe einen Weg, dies ohne zusätzliche Module für so winzige und gewöhnliche Dinge zu tun, aber dies ist das Beste, was ich mir vorstellen kann.

Update: Sollte jetzt unter Windows (getestetes Windows 10) und auch unter Linux/Unix/BSD/Mac-Systemen funktionieren.

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);
    });
}
1
b01

// ohne Verwendung einer Drittanbieter-lib

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);
0
Amy

Extrem schnell und ausfallsicher

Sie können das lignator -Paket ( https://www.npmjs.com/package/lignator ) verwenden. Es ist schneller als jeder asynchrone Code (z. B. rimraf) und ausfallsicherer (insbesondere) in Windows, wo das Entfernen von Dateien nicht sofort erfolgt und Dateien möglicherweise von anderen Prozessen gesperrt werden).

4,36 GB Daten, 28 042 Dateien, 4 217 Ordner unter Windows wurden in 15 Sekunden entfernt, gegenüber rimrafs 60 Sekunden alte Festplatte

const lignator = require('lignator');

lignator.remove('./build/');
0
HankMoody

const fs = require('fs')
const path = require('path')

let _dirloc = '<path_do_the_directory>'

if(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!')
    }
}

0
Erisan Olasheni

Eine andere Alternative ist die Verwendung des Moduls fs-promise , das versprechende Versionen der Module fs-extra bereitstellt

sie könnten dann wie folgt schreiben:

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)

anmerkung: Für async/await ist eine aktuelle Version von nodejs erforderlich (7.6+).

0
Max Fichtelmann

Dies ist ein Ansatz, der Versprechen und zwei Hilfsfunktionen (An und Alle) verwendet, um das Versprechen zu lösen.

Es führt alle Aktionen asynchron aus.

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)
    }
}; 
0
Aecio Levy