Buat Direktori Saat Menulis Ke File Di Node.js

135

Saya telah bermain-main dengan Node.js dan menemukan sedikit masalah. Saya punya skrip yang berada di direktori bernama data. Saya ingin skrip untuk menulis beberapa data ke file dalam subdirektori dalam datasubdirektori. Namun saya mendapatkan kesalahan berikut:

{ [Error: ENOENT, open 'D:\data\tmp\test.txt'] errno: 34, code: 'ENOENT', path: 'D:\\data\\tmp\\test.txt' }

Kode tersebut adalah sebagai berikut:

var fs = require('fs');
fs.writeFile("tmp/test.txt", "Hey there!", function(err) {
    if(err) {
        console.log(err);
    } else {
        console.log("The file was saved!");
    }
}); 

Adakah yang bisa membantu saya mencari tahu bagaimana membuat Node.js membuat struktur direktori jika tidak keluar untuk menulis ke file?

Hirvesh
sumber
1
fs.promises.mkdir(path.dirname("tmp/test.txt"), {recursive: true}).then(x => fs.promises.writeFile("tmp/test.txt", "Hey there!"))
Offenso

Jawaban:

127

Node> 10.12.0

fs.mkdir sekarang menerima { recursive: true }opsi seperti:

// Creates /tmp/a/apple, regardless of whether `/tmp` and /tmp/a exist.
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
  if (err) throw err;
});

atau dengan janji:

fs.promises.mkdir('/tmp/a/apple', { recursive: true }).catch(console.error);

Node <= 10.11.0

Anda dapat menyelesaikan ini dengan paket seperti mkdirp atau fs-extra . Jika Anda tidak ingin menginstal paket, silakan lihat jawaban Tiago Peres França di bawah ini.

David Weldon
sumber
4
Itulah yang akan saya lakukan ... statistik itu membuat saya jengkel.
Aran Mulholland
perhatikan bahwa fs.promisesmasih eksperimental nodejs.org/dist/latest-v10.x/docs/api/…
lasec0203
132

Jika Anda tidak ingin menggunakan paket tambahan apa pun, Anda dapat memanggil fungsi berikut sebelum membuat file Anda:

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

function ensureDirectoryExistence(filePath) {
  var dirname = path.dirname(filePath);
  if (fs.existsSync(dirname)) {
    return true;
  }
  ensureDirectoryExistence(dirname);
  fs.mkdirSync(dirname);
}
Tiago Peres França
sumber
2
Ini harus digunakan statSyncsebagai gantinya existsSync, berdasarkan stackoverflow.com/questions/4482686/…
GavinR
1
pathjuga merupakan paket yang perlu diminta seperti fs: var path = require('path')jika ada orang yang bertanya-tanya. Lihat dokumentasi simpul .
Rafael Emshoff
9
fs.existsSyncadalah tidak usang , hanya fs.existsadalah.
zzzzBov
6
Ada beberapa kebingungan tentang apakah fungsi fs.existsSync telah ditinggalkan atau tidak. Pada awalnya, menurut pemahaman saya, saya pikir itu, jadi saya memperbarui jawaban untuk mencerminkan ini. Tapi sekarang, seperti yang ditunjukkan oleh @zzzzBov, dokumentasi dengan jelas menyatakan bahwa hanya fs.exists yang telah ditinggalkan, penggunaan fs.existsSync masih valid. Untuk alasan ini saya menghapus kode sebelumnya dan jawaban saya sekarang hanya berisi solusi yang lebih sederhana (dengan menggunakan fs.existsSync).
Tiago Peres França
1
@chrismarx bayangkan jalur berikut: "/home/documents/a/b/c/myfile.txt". "/ home / dokumen" ada, sementara semua yang ada di depannya tidak ada. Ketika "sureDirectoryExistence" dipanggil untuk pertama kalinya, dirname adalah "/ home / dokumen / a / b / c". Saya tidak dapat menghubungi fs.mkdirSync (dirname) sekarang karena "/ home / dokumen / a / b" juga tidak ada. Untuk membuat direktori "c", saya harus terlebih dahulu memastikan keberadaan "/ home / dokumen / a / b".
Tiago Peres França
43

Dengan node-fs-extra Anda dapat melakukannya dengan mudah.

Pasang itu

npm install --save fs-extra

Kemudian gunakan outputFilemetode ini. Dokumentasinya mengatakan:

Hampir sama dengan writeFile (yaitu menimpa), kecuali bahwa jika direktori induk tidak ada, itu dibuat.

Anda dapat menggunakannya dalam tiga cara:

Gaya panggilan balik

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

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

Menggunakan Janji

Jika Anda menggunakan janji , dan saya harap begitu, ini kodenya:

fse.outputFile('tmp/test.txt', 'Hey there!')
   .then(() => {
       console.log('The file was saved!');
   })
   .catch(err => {
       console.error(err)
   });

Versi sinkronisasi

Jika Anda ingin versi sinkronisasi, cukup gunakan kode ini:

fse.outputFileSync('tmp/test.txt', 'Hey there!')

Untuk referensi lengkap, periksa outputFiledokumentasi dan semua metode yang didukung node-fs-extra .

lifeisfoo
sumber
26

Peringatan plug tak tahu malu!

Anda harus memeriksa setiap direktori dalam struktur jalur yang Anda inginkan dan membuatnya secara manual jika tidak ada. Semua alat untuk melakukannya sudah ada di modul fode Node, tetapi Anda dapat melakukan semua itu hanya dengan modul mkpath saya: https://github.com/jrajav/mkpath

jrajav
sumber
1
apakah itu akan membuat file secara langsung atau hanya struktur direktori? Saya mencari solusi yang membuat file bersama dengan struktur direktori saat membuat file.
Hirvesh
Hanya struktur direktori. Anda akan mkdir / path terlebih dahulu dan, jika tidak ada kesalahan, lanjutkan menulis file Anda. Akan cukup sederhana untuk menulis fungsi untuk melakukan keduanya secara bersamaan, diberi path lengkap ke file untuk menulis - hanya memisahkan nama file menggunakan path.basename
jrajav
1
Sebenarnya, itu sangat sederhana sehingga saya menulisnya dalam 2 menit . :) (Belum diuji)
jrajav
Pembaruan: Diuji dan diedit, silakan coba lagi jika tidak bekerja pertama kali.
jrajav
8
@ Kiyura Apa bedanya dengan mkdirp yang banyak digunakan ?
David Weldon
9

Karena saya belum bisa berkomentar, saya memposting jawaban yang ditingkatkan berdasarkan solusi fantastis @ tiago-peres-frança (terima kasih!). Kode-nya tidak membuat direktori dalam kasus di mana hanya direktori terakhir yang hilang di jalur, misalnya inputnya adalah "C: / test / abc" dan "C: / test" sudah ada. Berikut ini cuplikan yang berfungsi:

function mkdirp(filepath) {
    var dirname = path.dirname(filepath);

    if (!fs.existsSync(dirname)) {
        mkdirp(dirname);
    }

    fs.mkdirSync(filepath);
}
micx
sumber
1
Itu karena solusi @ tiago mengharapkan path file . Dalam kasus Anda, abcditafsirkan sebagai file yang Anda butuhkan untuk membuat direktori. Untuk juga membuat abcdirektori, tambahkan file dummy ke jalur Anda, mis C:/test/abc/dummy.txt.
Sphinxxx
Gunakan rekursif:fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))
Offenso
1
@Offenso itu solusi terbaik, tetapi hanya untuk Node.js versi 10.12 ke atas.
Nickensoul
8

Saran saya adalah: cobalah untuk tidak bergantung pada dependensi ketika Anda dapat dengan mudah melakukannya dengan beberapa baris kode

Inilah yang ingin Anda capai dalam 14 baris kode:

fs.isDir = function(dpath) {
    try {
        return fs.lstatSync(dpath).isDirectory();
    } catch(e) {
        return false;
    }
};
fs.mkdirp = function(dirname) {
    dirname = path.normalize(dirname).split(path.sep);
    dirname.forEach((sdir,index)=>{
        var pathInQuestion = dirname.slice(0,index+1).join(path.sep);
        if((!fs.isDir(pathInQuestion)) && pathInQuestion) fs.mkdirSync(pathInQuestion);
    });
};
Alex C.
sumber
1
Bukankah baris ketiga akan lebih baik seperti ini? return fs.lstatSync(dpath).isDirectory(), jika tidak, apa yang akan terjadi jika isDirectory () mengembalikan false?
Giorgio Aresu
2
Gunakan rekursif:fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))
Offenso
1
@Offenso itu tidak didukung oleh node 8
Ievgen Naida
2

Saya baru saja menerbitkan modul ini karena saya membutuhkan fungsi ini.

https://www.npmjs.org/package/filendir

Ini bekerja seperti pembungkus di sekitar metode Node.js fs. Jadi Anda dapat menggunakannya dengan cara yang persis sama dengan fs.writeFiledan fs.writeFileSync(baik async dan sinkron menulis)

Kev
sumber