How to create full path with node's fs.mkdirSync? Ask Question

How to create full path with node's fs.mkdirSync? Ask Question

I'm trying to create a full path if it doesn't exist.

The code looks like this:

var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest); 

This code works great as long as there is only one subdirectory (a newDest like 'dir1') however when there is a directory path like ('dir1/dir2') it fails with Error: ENOENT, no such file or directory

I'd like to be able to create the full path with as few lines of code as necessary.

I read there is a recursive option on fs and tried it like this

var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest,'0777', true);

I feel like it should be that simple to recursively create a directory that doesn't exist. Am I missing something or do I need to parse the path and check each directory and create it if it doesn't already exist?

I'm pretty new to Node. Maybe I'm using an old version of FS?

ベストアンサー1

Update

NodeJS version 10.12.0 has added a native support for both mkdir and mkdirSync to create a directory recursively with recursive: true option as the following:

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

And if you prefer fs Promises API, you can write

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

Original Answer

ディレクトリが存在しない場合は再帰的に作成します。(依存関係なし)

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

使用法

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

デモ

それを試してみてください!

説明

  • [更新]このソリューションは、EISDIRMac や Windows などのEPERMプラットフォーム固有のエラーを処理しますEACCES。@PediT.、@JohnQ、@deed02392、@robyoder、@Almenon による報告コメントに感謝します。
  • このソリューションは相対パス絶対パスの両方を処理します。@john のコメントに感謝します。
  • 相対パスの場合、ターゲット ディレクトリは現在の作業ディレクトリに作成 (解決) されます。現在のスクリプト ディレクトリを基準に解決するには、 を渡します{isRelativeToScript: true}
  • クロスプラットフォームの問題を回避するには、連結だけでなくおよびpath.sepを使用します。path.resolve()/
  • fs.mkdirSync競合状態を処理するために、 がスローされた場合にエラーを使用して処理しますtry/catch。別のプロセスが と の呼び出しの間にファイルを追加して、例外が発生する可能性がありfs.existsSync()ますfs.mkdirSync()
    • これを実現するもう 1 つの方法は、ファイルが存在するかどうかを確認してから作成することです。つまり、 です。if (!fs.existsSync(curDir) fs.mkdirSync(curDir);ただし、これは競合状態に対してコードを脆弱にするアンチパターンです。ディレクトリの存在チェックに関する @GershomMaes のコメントに感謝します。
  • デストラクチャリングをサポートするには、 Node v6以降が必要です。(古い Node バージョンでこのソリューションを実装する際に問題がある場合は、コメントを残してください)

おすすめ記事