Node.jsを使用して存在しないディレクトリを作成するにはどうすればよいですか?


656

これが存在しない場合にディレクトリを作成する正しい方法ですか?スクリプトに対する完全なアクセス許可があり、他のユーザーが読み取り可能である必要があります。

var dir = __dirname + '/upload';
if (!path.existsSync(dir)) {
    fs.mkdirSync(dir, 0744);
}

回答:


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

if (!fs.existsSync(dir)){
    fs.mkdirSync(dir);
}

28
アプリの起動時または初期化時にこの操作を実行している場合は、非同期で実行した場合と同じように実行をブロックしても問題ありません。定期的な操作としてディレクトリを作成する場合、その悪い習慣はおそらくパフォーマンスの問題を引き起こさないでしょうが、それでも悪い習慣です。アプリの起動またはその他の1回限りの操作にのみ使用します。
— tsturzl 2015

20
existsSync()は廃止予定ではなく、exists()は廃止予定です-nodejs.org/api/fs.html#fs_fs_existssync_path
— Ian Chadwick

* Syncメソッドの使用は、通常、
— ノーノーです。

14
同期メソッドを使用すると、ローカルスクリプトなどに適していますが、サーバーには明らかに適していません。
— 桟橋

そのブロックがsetTimeoutで囲まれている場合、非同期です..................................
— ブライアングレイス

185

いいえ、いくつかの理由があります。

  1. pathモジュールはありませんexists/ existsSyncメソッドを。fsモジュール内にあります。(おそらくあなたはあなたの質問にタイプミスをしただけですか?)

  2. ドキュメントでは、の使用を明示的に推奨していませんexists。

    fs.exists()時代錯誤であり、歴史的な理由でのみ存在します。独自のコードで使用する理由はほとんどありません。

    特に、開く前にファイルが存在するかどうかを確認することは、競合状態に対して脆弱なままになるアンチパターンです。別のプロセスがfs.exists()との呼び出しの間にファイルを削除する可能性がありますfs.open()。ファイルを開いて、そこにないときにエラーを処理するだけです。

    ファイルではなくディレクトリについて話しているので、このアドバイスは無条件にを呼び出しmkdirて無視する必要があることを意味しますEEXIST。

  3. 一般に、* Syncメソッドは使用しないでください。それらはブロックしているので、ディスクにアクセスしている間、プログラム内で他に何も起こり得ません。これは非常にコストのかかる操作であり、かかる時間はノードのイベントループの中心的な前提を破ります。

    * Syncメソッドは通常、単一目的のクイックスクリプト(1つの処理を行ってから終了するスクリプト)では問題ありませんが、サーバーを作成しているときにはほとんど使用しないでください。入出力要求の。複数のクライアント要求がI / O操作を必要とする場合、サーバーはすぐに停止します。


    Syncサーバーアプリケーションで* メソッドの使用を検討するのは、起動時に1 回(そして1回だけ)発生する操作だけです。たとえば、require 実際にを使用readFileSyncしてモジュールをロードします。

    それでも、多くの同期I / Oがサーバーの起動時間を不必要に遅くする可能性があるため、注意が必要です。


    代わりに、非同期I / Oメソッドを使用する必要があります。

したがって、これらのアドバイスをまとめると、次のような結果になります。

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

そして、次のように使用できます。

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

もちろん、これは次のようなエッジケースを考慮していません

  • プログラムの実行中にフォルダが削除された場合はどうなりますか?(起動時に一度だけ存在することを確認すると仮定)
  • フォルダがすでに存在しているが、権限が間違っている場合はどうなりますか?

1
SyntaxErrorを回避する方法はありますか:8進リテラルは厳密モードでは許可されていませんか?
— ウィッシャー、2014年

8
10進数として書きます。0744 == 484。
— josh3736 2014年


この「マスク」フラグは2019年にも関係がありますか?それの目的は何でしたか?
— oldboy

これはUNIXファイルモード、つまりディレクトリの読み取り/書き込み権限です。
— josh3736


33

このmkdirメソッドには、存在しないパスにディレクトリを再帰的に作成し、存在するディレクトリを無視する機能があります。

ノードV10 / 11ドキュメント:

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

注:fs最初に組み込みモジュールをインポートする必要があります。

次に、ネイティブESモジュール(フラグが有効で.mjs拡張子が付いている)を活用し、非ルートパスを処理し、完全パス名を説明する、もう少し堅牢な例を示します。

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');
       }
    });
}

のように使えますcreateDirectories('/components/widget/widget.js');。

そしてもちろん、おそらく、async / awaitでpromiseを使用して、ディレクトリの作成時にファイルをより読みやすく同期的に見る方法でファイルの作成を活用することで、もっと豪華にしたいと思うでしょう。しかし、それは質問の範囲を超えています。


1
なぜconst __dirname = path.resolve(); 組み込みの__dirnameを使用しませんか?
— TamusJRoyce


20

mkdirフォルダーが存在する場合は、エラーを使用してキャッチできます。
これは非同期(ベストプラクティス)で安全です。

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

(オプションで、モードに2番目の引数を追加します。)


他の考え:

  1. thenを使用するか、ネイティブのpromisifyを使用して待つことができます。

    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. (テストされていない)のような独自のpromiseメソッドを作成できます。

    let mkdirAsync = (path, mode) => new Promise(
       (resolve, reject) => mkdir (path, mode, 
          err => (err && err.code !== 'EEXIST') ? reject(err) : resolve()
          )
       )
    
  3. 同期チェックでは、以下を使用できます。

    fs.existsSync(path) || fs.mkdirSync(path)
  4. または、ライブラリを使用することもできます。

    • mkdirp(フォルダを実行するだけ)
    • fsextra(スーパーセットfs、たくさんの便利なものを追加)

1
有望なアプローチ#1の場合、キャッチを再配置できます。 mkdir('/path').catch(err => { if (err.code != 'EEXIST') throw err;}).then(myFunc);
— クールになる何

!==代わりに使用!=
— Quentin Roy

18

FS-余分なパッケージあなたがこれを行うことができますワンライナー:

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

const dir = '/tmp/this/path/does/not/exist';
fs.ensureDirSync(dir);

そのような過小評価された答え!fs-extraは私にとって必需品になりました。フォルダーが存在するかどうかを確認するために、10行以上を正義で書くのはおかしいと思います...
— 538ROMEO

10

最良の解決策は、node-fs-extraと呼ばれるnpmモジュールを使用することです。それはmkdirあなたが言及したディレクトリを作成すると呼ばれるメソッドを持っています。長いディレクトリパスを指定すると、親フォルダーが自動的に作成されます。モジュールはnpmモジュールのスーパーセットであるfsためfs、このモジュールを追加すると、すべての関数を使用できます。


6
var dir = 'path/to/dir';
try {
  fs.mkdirSync(dir);
} catch(e) {
  if (e.code != 'EEXIST') throw e;
}

4
Node.js v7.4.0の場合、ドキュメントにfs.exists()は非推奨であると記載されてfs.existsSync()いますが、非推奨ではありません。fs.existsSync()減価償却済みであることを示すリンクをリソースに追加できますか?
— フランシス2017年

1
コードのみの回答は、将来この質問に来るユーザーにとってあまり役に立ちません。回答を編集して、コードが元の問題を解決する理由を説明してください
— yivi

3
@francis、うーん、Node.js v5、nodejs.org
— docs /

1
ありがとう!関数はバージョン0.12に存在し、バージョン4および5で廃止され、バージョン6および7で復元されたようです...ゾンビ関数の種類...
— フランシス

1
はい、明らかにそれがされないのと、今は非推奨Apr 2018:nodejs.org/api/fs.html#fs_fs_existssync_path
— レオン-ハンリー

5
    var filessystem = require('fs');
    var dir = './path/subpath/';

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

これはあなたを助けるかもしれません:)


5

ENOENT:そのようなファイルまたはディレクトリはありません

解決

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

1
これは機能しています。ありがとう
— Aljohn Yamaro

3

私はjosh3736の回答のTypescript Promiseリファクタリングを追加したいと思います。

これは同じことを行い、同じエッジケースを持ちます。たまたまPromises、typescript typedefsを使用し、「use strict」で動作します。

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

3

ノード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;
    }
  }
})();

2

次の例のように、ノードファイルシステムコマンドfs.statを使用してdirが存在するかどうかを確認し、fs.mkdirを使用してコールバック付きのディレクトリを作成するか、fs.mkdirSyncを使用してコールバックなしのディレクトリを作成できます。

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

1

次に、ディレクトリを再帰的に作成するための小さな関数を示します。

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
  }, '')
}

0

async / awaitを使用する:

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

約束する必要がありますfs:

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

const fs = bluebird.promisifyAll(nodeFs);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.