Node.js membuat folder atau menggunakan yang sudah ada

186

Saya sudah membaca dokumentasi Node.js dan, kecuali jika saya melewatkan sesuatu, ia tidak memberi tahu parameter apa yang terkandung dalam operasi tertentu, khususnya fs.mkdir(). Seperti yang Anda lihat di dokumentasi, itu tidak terlalu banyak.

Saat ini, saya memiliki kode ini, yang mencoba membuat folder atau menggunakan yang sudah ada sebagai gantinya:

fs.mkdir(path,function(e){
    if(!e || (e && e.code === 'EEXIST')){
        //do something with contents
    } else {
        //debug
        console.log(e);
    }
});

Tetapi saya bertanya-tanya apakah ini cara yang tepat untuk melakukannya? Apakah memeriksa kode EEXISTmerupakan cara yang benar untuk mengetahui bahwa folder tersebut sudah ada? Saya tahu saya bisa melakukannya fs.stat()sebelum membuat direktori, tetapi itu sudah menjadi dua hit ke sistem file.

Kedua, apakah ada dokumentasi lengkap atau setidaknya dokumentasi Node.js yang lebih terperinci yang memuat perincian tentang objek kesalahan apa, parameter apa yang menandakan, dll.

Joseph
sumber
31
Nitpick kecil, tetapi singkirkan e &&. Jika !egagal, maka Anda tahu eitu benar.
I Hate Lazy

Jawaban:

236

Cara yang baik untuk melakukannya adalah dengan menggunakan modul mkdirp .

$ npm install mkdirp

Gunakan untuk menjalankan fungsi yang memerlukan direktori. Callback dipanggil setelah jalur dibuat atau jika jalur memang sudah ada. Kesalahan errdiatur jika mkdirp gagal membuat jalur direktori.

var mkdirp = require('mkdirp');
mkdirp('/tmp/some/path/foo', function(err) { 

    // path exists unless there was an error

});
Teemu Ikonen
sumber
3
Menurut saya jawaban yang benar (baca 'tanpa ketergantungan-ditambahkan') adalah jawaban yang paling rendah, oleh @Raugaral, menggunakan fs.exists(Sync).
Ricardo Pedroni
@meawoppl, ini adalah 'makedirectory'p. 'P' tidak diketahui.
andrew
4
@ RicardoPedroni Cara yang benar adalah dengan menggunakan modul. Modul biasanya dengan sepenuh hati berusaha menyelesaikan satu masalah, dan seringkali dipertahankan. Anda dapat memperbaruinya dengan mudah dengan npm. Selain itu, Anda harus menghindari penggunaan fs.exists [Sync] karena penggunaannya menyiratkan kondisi ras.
1j01
16
@ 1j01 Saya tidak percaya cara yang benar adalah dengan menggunakan modul jika platform mendukung operasi secara native. Itu jalan menuju kekacauan. Saya harus setuju bahwa ada jawaban yang lebih baik dari sudut pandang teknis.
c ..
2
@ 1j01 Juga, menggunakan operasi Sinkronisasi menyiratkan kondisi balapan karena penggunaannya adalah resolusi bagi mereka.
c ..
193

Sunting: Karena jawaban ini sangat populer, saya telah memperbaruinya untuk mencerminkan praktik terkini.

Node> = 10

{ recursive: true }Opsi baru Node fssekarang memungkinkan ini secara asli. Opsi ini meniru perilaku UNIX mkdir -p. Itu akan secara rekursif memastikan setiap bagian dari jalan ada, dan tidak akan membuat kesalahan jika ada yang melakukannya.

(Catatan: mungkin masih ada kesalahan seperti EPERMatau EACCESS, jadi lebih baik jika masih membungkusnya try {} catch (e) {}jika implementasi Anda rentan terhadapnya.)

Versi sinkron.

fs.mkdirSync(dirpath, { recursive: true })

Versi async

await fs.promises.mkdir(dirpath, { recursive: true })

Versi Node yang lebih lama

Dengan menggunakan try {} catch (err) {}, Anda dapat mencapai ini dengan sangat anggun tanpa menemui kondisi balapan.

Untuk mencegah waktu mati antara memeriksa keberadaan dan membuat direktori, kami hanya mencoba membuatnya lurus ke atas, dan mengabaikan kesalahan jika itu EEXIST(direktori sudah ada).

Namun, jika kesalahannya tidak EEXIST, kita harus melempar kesalahan, karena kita bisa berurusan dengan sesuatu seperti EPERMatauEACCES

function ensureDirSync (dirpath) {
  try {
    return fs.mkdirSync(dirpath)
  } catch (err) {
    if (err.code !== 'EEXIST') throw err
  }
}

Untuk mkdir -p-seperti perilaku rekursif, misalnya ./a/b/c, Anda harus menyebutnya pada setiap bagian dari dirpath itu, misalnya ./a, ./a/b,.a/b/c

Christophe Marois
sumber
var fs = Npm.require ('fs'); var dir = process.env.PWD + '/ file / users /' + this.userId + '/'; coba {fs.mkdirSync (dir); } catch (e) {if (e.code! = 'EEXIST') lempar e; }
Aaron
Saya mencoba kode Anda, membuat skrip js yang menggunakan pembuatan katalog seperti ini: mkdirpSync (path.join (__ dirname, 'first', 'second', 'third', 'ololol', 'works')); Tetapi mendapat kesalahan ini: $ node 1.js fs.js: 747 return binding.mkdir (pathModule._makeLong (path), ^ Kesalahan: EPERM, operasi tidak diizinkan 'C: \' saat Kesalahan (asli) di Object.fs. mkdirSync (fs.js: 747: 18) di mkdirpSync (C: \ Users \ MAXIM \ Desktop \ test \ 1.js: 15: 8) di Object. <anonymous> (C: \ Users \ MAXIM \ Desktop \ test \ 1.js: 19: 1) ... Bisakah Anda menyarankan apa yang bisa salah? Digunakan pada windows jelas :)
Alendorff
EPERM tampaknya seperti masalah izin, jadi skripnya tidak akan melakukan eksekusi yang rusak
Christophe Marois
Saya pikir itu akan lebih baik: var mkdirpSync = function (dirpath) {var parts = dirpath.split (path.sep); untuk (var i = 1; i <= parts.length; i ++) {coba {fs.mkdirSync (path.join.apply (null, parts.slice (0, i))); } catch (error) {if (error.code! = 'EEXIST') {throw error; }}}}
manish
1
peringatan: tidak berfungsi jika jalur Anda dimulai dengan /
acemtp
62

Jika Anda ingin liner cepat dan kotor, gunakan ini:

fs.existsSync("directory") || fs.mkdirSync("directory");
marekventur
sumber
1
fs.existssudah ditinggalkan: nodejs.org/api/fs.html#fs_fs_exists_path_callback
adius
7
fs.existsSync (...) tidak usang, jadi jawaban ini sepertinya tidak masalah.
Dan Haywood
Kepala! Tidak akan bekerja untuk "dir / foo / bar" yaitu tidak memiliki fitur flag mkdir -p
Karl Pokus
Ini juga memiliki kondisi balapan
Evert
26

Node docs untuk fs.mkdirdasarnya tunduk pada halaman manual Linux untuk mkdir(2). Itu menunjukkan bahwa EEXISTjuga akan ditunjukkan jika jalur ada tetapi bukan direktori yang membuat kasus sudut canggung jika Anda pergi rute ini.

Anda mungkin lebih baik memanggil fs.statyang akan memberi tahu Anda apakah jalur itu ada dan apakah itu direktori dalam satu panggilan. Untuk (apa yang saya asumsikan) kasus normal di mana direktori sudah ada, itu hanya satu sistem file hit.

fsMetode modul ini adalah pembungkus tipis di sekitar API C asli sehingga Anda harus memeriksa halaman manual yang dirujuk dalam dokumen node.js untuk detailnya.

JohnnyHK
sumber
19
Panggilan statsebelumnya mkdirberpotensi untuk kondisi balapan - ingatlah ini.
Roger Lipscombe
24

Anda bisa menggunakan ini:

if(!fs.existsSync("directory")){
    fs.mkdirSync("directory", 0766, function(err){
        if(err){
            console.log(err);
            // echo the result back
            response.send("ERROR! Can't make the directory! \n");
        }
    });
}
Raugaral
sumber
1
-1. Saya tidak percaya ini berfungsi, statSyncakan melempar kesalahan jika entitas tidak ada sama sekali, menabrak kode. Anda harus membungkus ini dalam satu try/catchblok.
Chris Foster
2
Maaf saya salah. ubah "statSync" menjadi "existSync"
Raugaral
5
Menurut nodejs.org/api/fs.html#fs_fs_mkdirsync_path_mode , varian Sync dari mkdir tidak menerima panggilan balik
danwellman
1
Menurut nodejs.org/api/fs.html#fs_fs_existssync_path , fs.existsSync()dan fs.exists()akan dihentikan.
pau.moreno
7

Saya mengusulkan solusi tanpa modul (modul akumulasi tidak pernah direkomendasikan untuk pemeliharaan terutama untuk fungsi kecil yang dapat ditulis dalam beberapa baris ...):

PEMBAHARUAN TERAKHIR :

Di v10.12.0, opsi rekursif NodeJS impletement:

// Create recursive folder
fs.mkdir('my/new/folder/create', { recursive: true }, (err) => { if (err) throw err; });

PEMBARUAN:

// Get modules node
const fs   = require('fs');
const path = require('path');

// Create 
function mkdirpath(dirPath)
{
    if(!fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK))
    {
        try
        {
            fs.mkdirSync(dirPath);
        }
        catch(e)
        {
            mkdirpath(path.dirname(dirPath));
            mkdirpath(dirPath);
        }
    }
}

// Create folder path
mkdirpath('my/new/folder/create');
Liberator
sumber
fs.exists()ditinggalkan dalam simpul v9. gunakan fs.access()saja. (kembali undefinedjika file ada; jika tidak ada kesalahan ENOENT)
chharvey
Tanpa paket npm, itu berfungsi. Itu kode yang berharga. Terima kasih
Karthik Sridharan
Yang ini lebih baik untuk membuat folder di bawah jalur panjang yang ada;) Terima kasih, bung.
Tsung Goh
1
Bagaimana dengan fs.mkdirSync('my/new/folder/create', {recursive: true})?
saitho
Terima kasih! Saya memperbarui posting saya untuk membantu orang lain. Node 10.12.0 terlalu baru.
Liberateur
4

Anda juga dapat menggunakan fs-extra , yang menyediakan banyak operasi file yang sering digunakan.

Kode sampel:

var fs = require('fs-extra')

fs.mkdirs('/tmp/some/long/path/that/prob/doesnt/exist', function (err) {
  if (err) return console.error(err)
  console.log("success!")
})

fs.mkdirsSync('/tmp/another/path')

dokumen di sini: https://github.com/jprichardson/node-fs-extra#mkdirsdir-callback

Geng Jiawen
sumber
4

Berikut adalah kode ES6 yang saya gunakan untuk membuat direktori (ketika tidak ada):

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

function createDirectory(directoryPath) {
  const directory = path.normalize(directoryPath);

  return new Promise((resolve, reject) => {
    fs.stat(directory, (error) => {
      if (error) {
        if (error.code === 'ENOENT') {
          fs.mkdir(directory, (error) => {
            if (error) {
              reject(error);
            } else {
              resolve(directory);
            }
          });
        } else {
          reject(error);
        }
      } else {
        resolve(directory);
      }
    });
  });
}

const directoryPath = `${__dirname}/test`;

createDirectory(directoryPath).then((path) => {
  console.log(`Successfully created directory: '${path}'`);
}).catch((error) => {
  console.log(`Problem creating directory: ${error.message}`)
});

catatan:

  • Di awal createDirectoryfungsi, saya menormalkan jalur untuk menjamin bahwa tipe jalur pemisah sistem operasi akan digunakan secara konsisten (mis. Ini akan berubah C:\directory/testmenjadi C:\directory\test(saat berada di Windows)
  • fs.existssudah usang , itu sebabnya saya gunakan fs.statuntuk memeriksa apakah direktori sudah ada
  • Jika direktori tidak ada, kode kesalahan akan menjadi ENOENT( E rror NO ENT ry)
  • Direktori itu sendiri akan dibuat menggunakan fs.mkdir
  • Saya lebih suka fungsi asynchronous fs.mkdirdaripada itu memblokir mitra fs.mkdirSyncdan karena pembungkusnya Promiseakan dijamin bahwa jalur direktori hanya akan dikembalikan setelah direktori berhasil dibuat
Benny Neugebauer
sumber
Terima kasih atas solusi bersih yang tidak melibatkan modul yang tidak perlu. Ini bekerja dengan baik untuk saya. Saya berharap ada lebih banyak jawaban seperti ini!
Ken Lyon
3

Anda sebaiknya tidak menghitung hit sistem file saat Anda kode dalam Javascript, menurut saya. Namun, (1) stat& mkdirdan (2) mkdirdan memeriksa (atau membuang) kode kesalahan, kedua cara adalah cara yang benar untuk melakukan apa yang Anda inginkan.

Chul-Woong Yang
sumber
-1, saya tidak melihat bagaimana mengecek atau membuang keduanya bisa menjadi cara yang tepat untuk melakukannya. Ini bukan jawaban.
Matt Ball
Ini cara yang bagus untuk mkdir direktori atau menggunakan yang sudah ada. Saya tidak mengerti mengapa Anda tidak melihat. Memeriksa kode kesalahan itu sopan, sedangkan membuang kode kesalahan itu bagus. tidakkah kamu setuju
Chul-Woong Yang
1
Mungkin ini masalah kendala bahasa, tapi saya membaca ini karena tidak menjawab pertanyaan yang diajukan OP.
Matt Ball
Saya mengerti apa maksud Anda. Namun, saya percaya bahwa ada banyak cara untuk melakukan hal yang benar. Terima kasih.
Chul-Woong Yang
2

buat direktori nama dinamis untuk setiap pengguna ... gunakan kode ini

***suppose email contain user mail address***

var filessystem = require('fs');
var dir = './public/uploads/'+email;

if (!filessystem.existsSync(dir)){
  filessystem.mkdirSync(dir);

}else
{
    console.log("Directory already exist");
}
Adiii
sumber
1

Anda dapat melakukan semua ini dengan modul Sistem File.

const
  fs = require('fs'),
  dirPath = `path/to/dir`

// Check if directory exists.
fs.access(dirPath, fs.constants.F_OK, (err)=>{
  if (err){
    // Create directory if directory does not exist.
    fs.mkdir(dirPath, {recursive:true}, (err)=>{
      if (err) console.log(`Error creating directory: ${err}`)
      else console.log('Directory created successfully.')
    })
  }
  // Directory now exists.
})

Anda bahkan tidak perlu memeriksa apakah direktori tersebut ada. Kode berikut juga menjamin bahwa direktori sudah ada atau dibuat.

const
  fs = require('fs'),
  dirPath = `path/to/dir`

// Create directory if directory does not exist.
fs.mkdir(dirPath, {recursive:true}, (err)=>{
  if (err) console.log(`Error creating directory: ${err}`)
  // Directory now exists.
})
orang tua
sumber
0

Jawaban Raugaral tetapi dengan fungsionalitas -p. Jelek, tapi berhasil:

function mkdirp(dir) {
    let dirs = dir.split(/\\/).filter(asdf => !asdf.match(/^\s*$/))
    let fullpath = ''

    // Production directory will begin \\, test is on my local drive.
    if (dirs[0].match(/C:/i)) {
        fullpath = dirs[0] + '\\'
    }
    else {
        fullpath = '\\\\' + dirs[0] + '\\'
    }

    // Start from root directory + 1, build out one level at a time.
    dirs.slice(1).map(asdf => {
        fullpath += asdf + '\\'
        if (!fs.existsSync(fullpath)) {
            fs.mkdirSync(fullpath)
        }
    })
}//mkdirp
pengguna8675309
sumber
0

Sama seperti alternatif yang lebih baru untuk jawaban Teemu Ikonen , yang sangat sederhana dan mudah dibaca, adalah dengan menggunakan ensureDirmetode fs-extrapaket.

Itu tidak hanya dapat digunakan sebagai pengganti terang-terangan untuk fsmodul built in , tetapi juga memiliki banyak fungsi lain selain fungsi fspaket.

The ensureDirmetode, seperti namanya, memastikan bahwa direktori ada. Jika struktur direktori tidak ada, itu dibuat. Seperti mkdir -p. Bukan hanya folder akhir, sebaliknya seluruh jalur dibuat jika belum ada.

yang disediakan di atas adalah asyncversi itu. Ini juga memiliki metode sinkron untuk melakukan ini dalam bentuk ensureDirSyncmetode.

Rai
sumber
0

@ Jawaban Liberateur di atas tidak bekerja untuk saya (Node v8.10.0). Sedikit modifikasi berhasil tetapi saya tidak yakin apakah ini cara yang benar. Tolong sarankan.

// Get modules node
const fs   = require('fs');
const path = require('path');

// Create
function mkdirpath(dirPath)
{
    try {
        fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
    }
    catch(err) {
        try
        {
            fs.mkdirSync(dirPath);
        }
        catch(e)
        {
            mkdirpath(path.dirname(dirPath));
            mkdirpath(dirPath);
        }
    }
}

// Create folder path
mkdirpath('my/new/folder/create');
nik
sumber