Come scrivere un file se la cartella principale non esiste?


93

Ho bisogno di scrivere il file nel seguente percorso:

fs.writeFile('/folder1/folder2/file.txt', 'content', function () {…});

Ma il '/folder1/folder2'percorso potrebbe non esistere. Quindi ottengo il seguente errore:

messaggio = ENOENT, apri /folder1/folder2/file.txt

Come posso scrivere contenuti su quel percorso?


2
fs.promises.mkdir(path.dirname('/folder1/folder2/file.txt'), {recursive: true}).then(x => fs.promises.writeFile('/folder1/folder2/file.txt', 'content'))
Offenso

Risposte:


127

Usa mkdirp in combinazione con path.dirnamefirst.

var mkdirp = require('mkdirp');
var fs = require('fs');
var getDirName = require('path').dirname;

function writeFile(path, contents, cb) {
  mkdirp(getDirName(path), function (err) {
    if (err) return cb(err);

    fs.writeFile(path, contents, cb);
  });
}

Se l'intero percorso esiste già, mkdirpè un noop. Altrimenti crea tutte le directory mancanti per te.

Questo modulo fa quello che vuoi: https://npmjs.org/package/writefile . Capito quando si cerca su Google "writefile mkdirp". Questo modulo restituisce una promessa invece di ricevere una richiamata, quindi assicurati di leggere prima un'introduzione alle promesse. Potrebbe effettivamente complicarti le cose.

La funzione che ho dato funziona comunque.


Quindi, se vogliamo aspettare che venga completato, dobbiamo mettere tutto quello che segue nella richiamata? C'è un altro modo?
pete

@pete se usi babel, potresti andare con async / wait in
Lucas Reppe Welander

11
Uso ricorsivo:fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))
Offenso

27

Trovo che il modo più semplice per farlo sia usare il metodo outputFile () dal modulo fs-extra .

Quasi uguale a writeFile (cioè sovrascrive), tranne per il fatto che se la directory padre non esiste, viene creata. le opzioni sono ciò che passeresti a fs.writeFile ().

Esempio:

var fs = require('fs-extra');
var file = '/tmp/this/path/does/not/exist/file.txt'

fs.outputFile(file, 'hello!', function (err) {
    console.log(err); // => null

    fs.readFile(file, 'utf8', function (err, data) {
        console.log(data); // => hello!
    });
});

Ha anche un supporto promettente fuori dagli schemi in questi giorni !.


19

Forse più semplicemente, puoi semplicemente usare il modulo npm fs-path .

Il tuo codice sarebbe quindi simile a:

var fsPath = require('fs-path');

fsPath.writeFile('/folder1/folder2/file.txt', 'content', function(err){
  if(err) {
    throw err;
  } else {
    console.log('wrote a file like DaVinci drew machines');
  }
});

18

modificare

La versione di NodeJS 10.12.0ha aggiunto un supporto nativo per entrambi mkdire mkdirSyncper creare il regista padre in modo ricorsivo con l' recursive: trueopzione come segue:

fs.mkdirSync(targetDir, { recursive: true });

E se preferisci fs Promises API, puoi scrivere

fs.promises.mkdir(targetDir, { recursive: true });

Risposta originale

Crea le directory padre in modo ricorsivo se non esistono! ( Zero dipendenze )

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

function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) {
  const sep = path.sep;
  const initDir = path.isAbsolute(targetDir) ? sep : '';
  const baseDir = isRelativeToScript ? __dirname : '.';

  return targetDir.split(sep).reduce((parentDir, childDir) => {
    const curDir = path.resolve(baseDir, parentDir, childDir);
    try {
      fs.mkdirSync(curDir);
    } catch (err) {
      if (err.code === 'EEXIST') { // curDir already exists!
        return curDir;
      }

      // To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
      if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure.
        throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
      }

      const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1;
      if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) {
        throw err; // Throw if it's just the last created dir.
      }
    }

    return curDir;
  }, initDir);
}

Utilizzo

// Default, make directories relative to current working directory.
mkDirByPathSync('path/to/dir');

// Make directories relative to the current script.
mkDirByPathSync('path/to/dir', {isRelativeToScript: true});

// Make directories with an absolute path.
mkDirByPathSync('/path/to/dir');

Demo

Provalo!

Spiegazioni

  • [AGGIORNAMENTO] Questa soluzione gestisce gli errori specifici della piattaforma come EISDIRper Mac e EPERMe EACCESper Windows.
  • Questa soluzione gestisce sia percorsi relativi che assoluti .
  • Nel caso di percorsi relativi, le directory di destinazione verranno create (risolte) nella directory di lavoro corrente. Per risolverli rispetto alla directory corrente dello script, passare {isRelativeToScript: true}.
  • Utilizzo path.sepe path.resolve(), non solo /concatenazione, per evitare problemi multipiattaforma.
  • Usare fs.mkdirSynce gestire l'errore con try/catchif lanciato per gestire le condizioni di competizione: un altro processo può aggiungere il file tra le chiamate a fs.existsSync()e fs.mkdirSync()e causa un'eccezione.
    • L'altro modo per ottenerlo potrebbe essere controllare se esiste un file e crearlo, cioè if (!fs.existsSync(curDir) fs.mkdirSync(curDir);. Ma questo è un anti-pattern che lascia il codice vulnerabile alle condizioni di gara.
  • Richiede Node v6 e versioni successive per supportare la destrutturazione. (Se hai problemi ad implementare questa soluzione con le vecchie versioni di Node, lasciami un commento)

3

Puoi usare

fs.stat('/folder1/folder2', function(err, stats){ ... });

statsè un fs.Statstipo di oggetto, puoi controllare stats.isDirectory(). A seconda dell'esame di erre statspuoi fare qualcosa fs.mkdir( ... )o lanciare un errore.

Riferimento

Aggiornamento: corrette le virgole nel codice.


Quindi non posso scrivere file usando il comando sibgle in nodejs?
Erik

2

Ecco la mia funzione personalizzata per creare directory in modo ricorsivo (senza dipendenze esterne):

var fs = require('fs');
var path = require('path');

var myMkdirSync = function(dir){
    if (fs.existsSync(dir)){
        return
    }

    try{
        fs.mkdirSync(dir)
    }catch(err){
        if(err.code == 'ENOENT'){
            myMkdirSync(path.dirname(dir)) //create parent dir
            myMkdirSync(dir) //create dir
        }
    }
}

myMkdirSync(path.dirname(filePath));
var file = fs.createWriteStream(filePath);

2

Ecco la mia funzione che funziona nel nodo 10.12.0. Spero che questo ti aiuti.

const fs = require('fs');
function(dir,filename,content){
        fs.promises.mkdir(dir, { recursive: true }).catch(error => { console.error('caught exception : ', error.message); });
        fs.writeFile(dir+filename, content, function (err) {
            if (err) throw err;
            console.info('file saved!');
        });
    }

2

Con node-fs-extra puoi farlo facilmente.

Installalo

npm install --save fs-extra

Quindi usa il metodo outputFile invece di writeFileSync

const fs = require('fs-extra');

fs.outputFile('tmp/test.txt', 'Hey there!', err => {
  if(err) {
    console.log(err);
  } else {
    console.log('The file was saved!');
  }
})

0

Ecco parte della risposta di Myrne Stol suddivisa come risposta separata:

Questo modulo fa quello che vuoi: https://npmjs.org/package/writefile . Capito quando si cerca su Google "writefile mkdirp". Questo modulo restituisce una promessa invece di ricevere una richiamata, quindi assicurati di leggere prima un'introduzione alle promesse. Potrebbe effettivamente complicarti le cose.


0
let name = "./new_folder/" + file_name + ".png";
await driver.takeScreenshot().then(
  function(image, err) {
    require('mkdirp')(require('path').dirname(name), (err) => {
      require('fs').writeFile(name, image, 'base64', function(err) {
        console.log(err);
      });
    });
  }
);

Le risposte di solo codice sono considerate di bassa qualità: assicurati di fornire una spiegazione su cosa fa il tuo codice e come risolve il problema. Aiuterà sia il richiedente che i futuri lettori se puoi aggiungere ulteriori informazioni nel tuo post. Vedi Spiegazione delle risposte interamente basate sul codice
Calos
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.