Bagaimana cara membuat direktori jika tidak ada menggunakan Node.js?

656

Apakah ini cara yang tepat untuk membuat direktori jika tidak ada. Itu harus memiliki izin penuh untuk skrip dan dapat dibaca oleh orang lain.

var dir = __dirname + '/upload';
if (!path.existsSync(dir)) {
    fs.mkdirSync(dir, 0744);
}
Whisher
sumber
1
Kemungkinan duplikat dari Node.js membuat folder atau menggunakan yang ada
Benny Neugebauer

Jawaban:

1280
var fs = require('fs');
var dir = './tmp';

if (!fs.existsSync(dir)){
    fs.mkdirSync(dir);
}
kenyal
sumber
28
Jika Anda melakukan operasi ini pada boot aplikasi atau inisialisasi, maka boleh saja untuk memblokir eksekusi karena Anda akan melakukan hal yang sama jika Anda melakukannya secara asinkron. Jika Anda menjadikan direktori sebagai operasi berulang, maka ini merupakan praktik buruk, tetapi mungkin tidak akan menyebabkan masalah kinerja, namun ini merupakan kebiasaan buruk. Hanya digunakan untuk mem-boot aplikasi Anda atau operasi satu kali.
tsturzl
20
existSync () tidak ditinggalkan, ada () meskipun - nodejs.org/api/fs.html#fs_fs_existssync_path
Ian Chadwick
menggunakan * Syncmetode biasanya tidak-tidak: tidak ingin memblokir acara loop
Max Heiber
14
Menggunakan metode sinkronisasi itu baik untuk skrip lokal dan semacamnya, jelas bukan ide yang baik untuk server.
Dermaga
Jika blok itu dikelilingi oleh setTimeout, async .....................
Bryan Grace
186

Tidak, karena berbagai alasan.

  1. The pathmodul tidak memiliki exists/ existsSyncmetode. Itu ada di fsmodul. (Mungkin Anda baru saja membuat kesalahan ketik pada pertanyaan Anda?)

  2. Dokumen secara eksplisit mencegah Anda menggunakan exists.

    fs.exists()adalah anakronisme dan hanya ada karena alasan historis. Seharusnya hampir tidak pernah ada alasan untuk menggunakannya dalam kode Anda sendiri.

    Khususnya, memeriksa apakah ada file sebelum membukanya, itu merupakan pola anti yang membuat Anda rentan terhadap kondisi balapan: proses lain dapat menghapus file antara panggilan ke fs.exists()dan fs.open(). Cukup buka file dan tangani kesalahannya saat tidak ada.

    Karena kita berbicara tentang direktori daripada file, saran ini menyiratkan Anda hanya harus memanggil mkdirdan mengabaikan tanpa syarat EEXIST.

  3. Secara umum, Anda harus menghindari Syncmetode * . Mereka memblokir, yang berarti sama sekali tidak ada hal lain dalam program Anda yang dapat terjadi saat Anda masuk ke disk. Ini adalah operasi yang sangat mahal, dan waktu yang diperlukan mematahkan asumsi inti dari simpul acara simpul.

    The * Syncmetode yang biasanya baik-baik saja di-tujuan tunggal skrip cepat (orang-orang yang melakukan satu hal dan kemudian keluar), tetapi harus hampir tidak pernah digunakan ketika Anda sedang menulis sebuah server: server Anda akan dapat merespon kepada siapa pun untuk seluruh durasi dari permintaan I / O. Jika beberapa permintaan klien memerlukan operasi I / O, server Anda akan sangat cepat terhenti.


    Satu-satunya waktu saya akan mempertimbangkan menggunakan Syncmetode * dalam aplikasi server adalah dalam operasi yang terjadi sekali (dan hanya sekali), pada saat startup. Misalnya, require sebenarnya digunakanreadFileSync untuk memuat modul.

    Meski begitu, Anda masih harus berhati-hati karena banyak I / O yang sinkron dapat memperlambat waktu startup server Anda.


    Sebagai gantinya, Anda harus menggunakan metode I / O asinkron.

Jadi jika kita mengumpulkan saran-saran itu, kita mendapatkan sesuatu seperti ini:

function ensureExists(path, mask, cb) {
    if (typeof mask == 'function') { // allow the `mask` parameter to be optional
        cb = mask;
        mask = 0777;
    }
    fs.mkdir(path, mask, function(err) {
        if (err) {
            if (err.code == 'EEXIST') cb(null); // ignore the error if the folder already exists
            else cb(err); // something else went wrong
        } else cb(null); // successfully created folder
    });
}

Dan kita bisa menggunakannya seperti ini:

ensureExists(__dirname + '/upload', 0744, function(err) {
    if (err) // handle folder creation error
    else // we're all good
});

Tentu saja, ini tidak termasuk kasus tepi seperti

  • Apa yang terjadi jika folder terhapus saat program Anda berjalan? (dengan asumsi Anda hanya memeriksa bahwa itu ada satu kali selama startup)
  • Apa yang terjadi jika folder sudah ada tetapi dengan izin yang salah?
josh3736
sumber
1
apakah ada cara untuk menghindari SyntaxError: Literal oktal tidak diperbolehkan dalam mode ketat?
Whisher
8
Tuliskan sebagai desimal. 0744 == 484.
josh3736
3
Alternatifnya adalah dengan menggunakan modul yang memanjang fs untuk memiliki fungsi ini seperti github.com/jprichardson/node-fs-extra
Bret
Apakah bendera "topeng" ini masih relevan di tahun 2019? apa tujuannya?
oldboy
Ini adalah mode file unix - izin baca / tulis direktori.
josh3736
44

Saya telah menemukan dan modul npm yang berfungsi seperti pesona untuk ini. Itu hanya melakukan mkdir secara rekursif ketika dibutuhkan, seperti "mkdir -p".

https://www.npmjs.com/package/mkdirp

Toni Gamez
sumber
34

The mkdirmetode memiliki kemampuan untuk secara rekursif membuat direktori apapun dalam jalur yang tidak ada, dan mengabaikan orang-orang yang melakukan.

Dari Node v10 / 11 docs :

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

CATATAN: Anda harus mengimpor fsmodul bawaan terlebih dahulu.

Sekarang inilah contoh yang lebih kuat yang memanfaatkan Modul ES asli (dengan flag diaktifkan dan ekstensi .mjs), menangani jalur non-root, dan menyumbang nama path lengkap:

import fs from 'fs';
import path from 'path';

createDirectories(pathname) {
   const __dirname = path.resolve();
   pathname = pathname.replace(/^\.*\/|\/?[^\/]+\.[a-z]+|\/$/g, ''); // Remove leading directory markers, and remove ending /file-name.extension
   fs.mkdir(path.resolve(__dirname, pathname), { recursive: true }, e => {
       if (e) {
           console.error(e);
       } else {
           console.log('Success');
       }
    });
}

Anda bisa menggunakannya seperti createDirectories('/components/widget/widget.js');.

Dan tentu saja, Anda mungkin ingin mendapatkan yang lebih mewah dengan menggunakan janji dengan async / menunggu untuk meningkatkan pembuatan file dengan cara yang terlihat lebih sinkron saat direktori dibuat; tapi, itu di luar ruang lingkup pertanyaan.

sedikit kurang
sumber
1
Mengapa const __dirname = path.resolve (); dan tidak menggunakan __dirname built-in?
TamusJRoyce
29

Untuk berjaga-jaga jika ada yang tertarik dengan versi satu baris. :)

//or in typescript: import * as fs from 'fs';
const fs = require('fs');
!fs.existsSync(dir) && fs.mkdirSync(dir);
LeOn - Han Li
sumber
Dugaan 1-liner sebenarnya bukan 1 baris.
Web hybrid dev
20

Anda bisa menggunakan mkdirdan menangkap kesalahan jika folder ada.
Ini async (praktik terbaik) dan aman.

fs.mkdir('/path', err => { 
    if (err && err.code != 'EEXIST') throw 'up'
    .. safely do your stuff here  
    })

(Secara opsional tambahkan argumen kedua dengan mode.)


Pikiran lain:

  1. Anda bisa menggunakannya saat itu atau menunggu dengan menggunakan promisify asli .

    const util = require('util'), fs = require('fs');
    const mkdir = util.promisify(fs.mkdir);
    var myFunc = () => { ..do something.. } 
    
    mkdir('/path')
        .then(myFunc)
        .catch(err => { if (err.code != 'EEXIST') throw err; myFunc() })
  2. Anda dapat membuat metode janji sendiri, seperti (belum diuji):

    let mkdirAsync = (path, mode) => new Promise(
       (resolve, reject) => mkdir (path, mode, 
          err => (err && err.code !== 'EEXIST') ? reject(err) : resolve()
          )
       )
  3. Untuk pemeriksaan sinkron, Anda dapat menggunakan:

    fs.existsSync(path) || fs.mkdirSync(path)
  4. Atau Anda dapat menggunakan perpustakaan, dua yang paling populer

    • mkdirp (hanya folder)
    • fsextra (supersets fs, menambahkan banyak hal berguna)
SamGoody
sumber
1
untuk pendekatan yang menjanjikan # 1, Anda dapat mengatur ulang tangkapan. mkdir('/path').catch(err => { if (err.code != 'EEXIST') throw err;}).then(myFunc);
What Would Be Cool
Dan gunakan !==sebagai ganti!=
Quentin Roy
18

Dengan paket fs-extra Anda dapat melakukan ini dengan one-liner :

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

const dir = '/tmp/this/path/does/not/exist';
fs.ensureDirSync(dir);
galki
sumber
Jawaban yang diremehkan seperti itu! fs-extra memiliki bacame yang harus dimiliki untukku. Saya pikir ini adalah abberasi untuk menulis 10+ baris juste untuk memeriksa apakah ada folder ...
538ROMEO
10

Solusi terbaik adalah dengan menggunakan modul npm yang disebut node-fs-extra . Ini memiliki metode yang disebut mkdiryang membuat direktori yang Anda sebutkan. Jika Anda memberikan jalur direktori yang panjang, itu akan membuat folder induk secara otomatis. Modul ini adalah set modul npm yang super fs, sehingga Anda dapat menggunakan semua fungsi fsjuga jika Anda menambahkan modul ini.

Abdul Vajid
sumber
6
var dir = 'path/to/dir';
try {
  fs.mkdirSync(dir);
} catch(e) {
  if (e.code != 'EEXIST') throw e;
}
Ping.Goblue
sumber
4
Untuk Node.js v7.4.0, dokumentasi menyatakan bahwa fs.exists()sudah usang, tetapi fs.existsSync()tidak. Bisakah Anda menambahkan tautan ke sumber daya pepatah yang fs.existsSync()didepresiasi?
francis
1
Jawaban hanya kode tidak sangat membantu bagi pengguna yang datang ke pertanyaan ini di masa mendatang. Harap edit jawaban Anda untuk menjelaskan mengapa kode Anda memecahkan masalah asli
yivi
3
@ Francis, hmm, saya sedang melihat Node.js v5, nodejs.org/docs/latest-v5.x/api/fs.html#fs_fs_exskscync_path
Ping.Goblue
1
Terima kasih! Tampaknya fungsi tersebut ada di versi 0.12, tidak digunakan lagi di versi 4 dan 5 dan dipulihkan di versi 6 dan 7 ... Jenis fungsi zombi ...
francis
1
Ya, tampaknya itu TIDAK ditinggalkan sekarang pada Apr 2018: nodejs.org/api/fs.html#fs_fs_existssync_path
LeOn - Han Li
5
    var filessystem = require('fs');
    var dir = './path/subpath/';

    if (!filessystem.existsSync(dir)){
        filessystem.mkdirSync(dir);
    }else
    {
        console.log("Directory already exist");
    }

Ini dapat membantu Anda :)

Wisnu S Babu
sumber
5

ENOENT: tidak ada file atau direktori tersebut

Larutan

const fs = require('fs')  // in javascript
import * as fs from "fs"  // in typescript
import fs from "fs"       // in typescript

// it will create the directory if it does not exist.
!fs.existsSync(`./assets/`) && fs.mkdirSync(`./assets/`, { recursive: true })
WasiF
sumber
1
ini berhasil, terima kasih
Aljohn Yamaro
3

Saya ingin menambahkan refactor Typescript Promise atas jawaban josh3736 .

Itu melakukan hal yang sama dan memiliki kasus tepi yang sama, kebetulan menggunakan Janji, mengetikkan huruf dan bekerja dengan "gunakan ketat".

// https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation
const allRWEPermissions = parseInt("0777", 8);

function ensureFilePathExists(path: string, mask: number = allRWEPermissions): Promise<void> {
    return new Promise<void>(
        function(resolve: (value?: void | PromiseLike<void>) => void,
            reject: (reason?: any) => void): void{
            mkdir(path, mask, function(err: NodeJS.ErrnoException): void {
                if (err) {
                    if (err.code === "EEXIST") {
                        resolve(null); // ignore the error if the folder already exists
                    } else {
                        reject(err); // something else went wrong
                    }
                } else {
                    resolve(null); // successfully created folder
                }
            });
    });
}
Nathan Cooper
sumber
3

Dengan Node 10 + ES6:

import path from 'path';
import fs from 'fs';

(async () => {
  const dir = path.join(__dirname, 'upload');

  try {
    await fs.promises.mkdir(dir);
  } catch (error) {
    if (error.code === 'EEXIST') {
      // Something already exists, but is it a file or directory?
      const lstat = await fs.promises.lstat(dir);

      if (!lstat.isDirectory()) {
        throw error;
      }
    } else {
      throw error;
    }
  }
})();
sdgfsdh
sumber
2

Anda dapat menggunakan perintah node File System fs.stat untuk memeriksa apakah dir ada dan fs.mkdir untuk membuat direktori dengan panggilan balik, atau fs.mkdirSync untuk membuat direktori tanpa panggilan balik, seperti contoh ini:

//first require fs
const fs = require('fs');

// Create directory if not exist (function)
const createDir = (path) => {
    // check if dir exist
    fs.stat(path, (err, stats) => {
        if (stats.isDirectory()) {
            // do nothing
        } else {
            // if the given path is not a directory, create a directory
            fs.mkdirSync(path);
        }
    });
};
Majid Jiji
sumber
1

Berikut adalah sedikit fungsi untuk secara rekursif membuat direktori:

const createDir = (dir) => {
  // This will create a dir given a path such as './folder/subfolder' 
  const splitPath = dir.split('/');
  splitPath.reduce((path, subPath) => {
    let currentPath;
    if(subPath != '.'){
      currentPath = path + '/' + subPath;
      if (!fs.existsSync(currentPath)){
        fs.mkdirSync(currentPath);
      }
    }
    else{
      currentPath = subPath;
    }
    return currentPath
  }, '')
}
Tuan Bennyny
sumber
0

Menggunakan async / tunggu:

const mkdirP = async (directory) => {
  try {
    return await fs.mkdirAsync(directory);
  } catch (error) {
    if (error.code != 'EEXIST') {
      throw e;
    }
  }
};

Anda harus berjanji fs:

import nodeFs from 'fs';
import bluebird from 'bluebird';

const fs = bluebird.promisifyAll(nodeFs);
sdgfsdh
sumber