web-dev-qa-db-ja.com

ノードのfs.mkdirSyncでフルパスを作成する方法?

存在しない場合はフルパスを作成しようとしています。

コードは次のようになります。

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

このコードは1つのサブディレクトリ( 'dir1'のようなnewDest)しかない限りはうまくいきますが、( 'dir1/dir2')のようなディレクトリパスがあるとで失敗しますエラー:ENOENTそのようなファイルやディレクトリはありません

必要な数のコード行でフルパスを作成できるようにしたいです。

私はfsに再帰的なオプションがあることを読み、このように試してみました

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

存在しないディレクトリを再帰的に作成するのはそれほど単純であるべきだと私は感じます。何かが足りないのですか、それともパスを解析して各ディレクトリをチェックし、まだ存在しない場合は作成する必要がありますか。

私はNodeが初めてです。たぶん私はFSの古いバージョンを使っていますか?

116

一つの選択肢は shelljs module を使うことです

npm install shelljs

var Shell = require('shelljs');
Shell.mkdir('-p', fullPath);

そのページから:

利用可能なオプション:

p:フルパス(必要に応じて中間ディレクトリを作成します)

他の人が指摘したように、他のより焦点を絞ったモジュールがあります。しかし、mkdirp以外には、他にもたくさんの便利なシェル操作(which、grepなど)があり、Windowsや* nixでも動作します

45
bryanmac

編集

NodeJSバージョン10では、次のように recursive: true オプションで再帰的にディレクトリを作成するためにmkdirmkdirSyncの両方のネイティブサポートが追加されました。

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

そして fs Promises API を好めば、書くことができます

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

元の答え

ディレクトリが存在しない場合は再帰的にディレクトリを作成してください。 (依存関係がない

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

デモ

試してみてください!

説明

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

もっと強固な答えはuse mkdirp を使うことです。

var mkdirp = require('mkdirp');

mkdirp('/path/to/dir', function (err) {
    if (err) console.error(err)
    else console.log('dir created')
});

次に、ファイルをフルパスに書き込みます。

fs.writeFile ('/path/to/dir/file.dat'....
73
cshotton

fs-extraは、ネイティブのfsモジュールに含まれていないファイルシステムメソッドを追加します。 fsの代わりになるのです。

fs-extraをインストールする

$ npm install --save fs-extra

const fs = require("fs-extra");
// Make sure the output directory is there.
fs.ensureDirSync(newDest);

同期と非同期のオプションがあります。

https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir.md

45
Deejers

Reduceを使用すると、各パスが存在するかどうかを確認し、必要に応じて作成することができます。このようにしても、追跡が簡単になります。編集した、@ Arvinのおかげで、path.sepを使用してプラットフォーム固有の適切なパスセグメントセパレータを取得する必要があります。

const path = require('path');

// Path separators could change depending on the platform
const pathToCreate = 'path/to/dir'; 
pathToCreate
 .split(path.sep)
 .reduce((prevPath, folder) => {
   const currentPath = path.join(prevPath, folder, path.sep);
   if (!fs.existsSync(currentPath)){
     fs.mkdirSync(currentPath);
   }
   return currentPath;
 }, '');
29
josebui

この機能はバージョン10.12.0でnode.jsに追加されたので、fs.mkdir()呼び出しの2番目の引数としてオプション{recursive: true}を渡すのと同じくらい簡単です。 公式文書の例 を参照してください。

外部モジュールやあなた自身の実装は必要ありません。

27
Capaj

私はこれが古い質問であることを知っています、しかしnodejs v10.12は今trueに設定されたrecursiveオプションでこれをネイティブにサポートします。 fs.mkdir

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

NodeJS> = 10では、fs.mkdirSync(path, { recursive: true })fs.mkdirSync を使うことができます。

4
William Penagos

Windowsの例(追加の依存関係やエラー処理はありません)

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

let dir = "C:\\temp\\dir1\\dir2\\dir3";

function createDirRecursively(dir) {
    if (!fs.existsSync(dir)) {        
        createDirRecursively(path.join(dir, ".."));
        fs.mkdirSync(dir);
    }
}

createDirRecursively(dir); //creates dir1\dir2\dir3 in C:\temp
2
Andrey Imshenik

あなたは次の機能を使用することができます

const recursiveUpload =(path:string)=> {const paths = path.split( "/")

const fullPath = paths.reduce((accumulator, current) => {
  fs.mkdirSync(accumulator)
  return `${accumulator}/${current}`
  })

  fs.mkdirSync(fullPath)

  return fullPath
}

だからそれは何をしますか:

  1. paths変数を作成します。ここで、すべてのパスを単独で配列の要素として格納します。
  2. 配列内の各要素の末尾に "/"を追加します。
  3. サイクルを作ります:
    1. インデックスが0から現在の反復までの配列要素の連結からディレクトリを作成します。基本的には再帰的です。

それが役立つことを願っています!

ちなみに、Node v10.12.0では追加の引数としてそれを与えることで再帰的なパス作成を使うことができます。

fs.mkdir('/tmp/a/Apple', { recursive: true }, (err) => { if (err) throw err; });

https://nodejs.org/api/fs.html#fs_fs_mkdirsync_path_options

2
hypeofpipe

単にフォルダが存在するかどうかを再帰的に確認し、存在しないかどうかを確認しながらフォルダを作成することができます。 (NO EXTERNAL LIBRARY

function checkAndCreateDestinationPath (fileDestination) {
    const dirPath = fileDestination.split('/');
    dirPath.forEach((element, index) => {
        if(!fs.existsSync(dirPath.slice(0, index + 1).join('/'))){
            fs.mkdirSync(dirPath.slice(0, index + 1).join('/')); 
        }
    });
}
1
Pulkit Aggarwal

あまりにも多くの答えがありますが、ここではパスを分割してから再度左から右へと構築することによって機能する再帰のない解決策があります。

function mkdirRecursiveSync(path) {
    let paths = path.split(path.delimiter);
    let fullPath = '';
    paths.forEach((path) => {

        if (fullPath === '') {
            fullPath = path;
        } else {
            fullPath = fullPath + '/' + path;
        }

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

WindowsとLinuxの互換性を気にする人は、上記の両方でスラッシュをダブルバックスラッシュ(\)に置き換えてください。TBH上記のコードは単にWindows上で動作し、より完全なソリューションクロスプラットフォームです。

1
Hamiora
const fs = require('fs');

try {
    fs.mkdirSync(path, { recursive: true });
} catch (error) {
    // this make script keep running, even when folder already exist
    console.log(error);
}
1
Choco Li

mouneer's 依存度ゼロの回答に基づいて、モジュールとして、もう少し初心者に優しいTypeScriptの変種を示します。

import * as fs from 'fs';
import * as path from 'path';

/**
* Recursively creates directories until `targetDir` is valid.
* @param targetDir target directory path to be created recursively.
* @param isRelative is the provided `targetDir` a relative path?
*/
export function mkdirRecursiveSync(targetDir: string, isRelative = false) {
    const sep = path.sep;
    const initDir = path.isAbsolute(targetDir) ? sep : '';
    const baseDir = isRelative ? __dirname : '.';

    targetDir.split(sep).reduce((prevDirPath, dirToCreate) => {
        const curDirPathToCreate = path.resolve(baseDir, prevDirPath, dirToCreate);
        try {
            fs.mkdirSync(curDirPathToCreate);
        } catch (err) {
            if (err.code !== 'EEXIST') {
                throw err;
            }
            // caught EEXIST error if curDirPathToCreate already existed (not a problem for us).
        }

        return curDirPathToCreate; // becomes prevDirPath on next call to reduce
    }, initDir);
}

これがnodejs用のmkdirpの必須バージョンです。

function mkdirSyncP(location) {
    let normalizedPath = path.normalize(location);
    let parsedPathObj = path.parse(normalizedPath);
    let curDir = parsedPathObj.root;
    let folders = parsedPathObj.dir.split(path.sep);
    folders.Push(parsedPathObj.base);
    for(let part of folders) {
        curDir = path.join(curDir, part);
        if (!fs.existsSync(curDir)) {
            fs.mkdirSync(curDir);
        }
    }
}
0
ubershmekel

ディレクトリを再帰的に作成する非同期の方法

import fs from 'fs'

const mkdirRecursive = function(path, callback) {
  let controlledPaths = []
  let paths = path.split(
    '/' // Put each path in an array
  ).filter(
    p => p != '.' // Skip root path indicator (.)
  ).reduce((memo, item) => {
    // Previous item prepended to each item so we preserve realpaths
    const prevItem = memo.length > 0 ? memo.join('/').replace(/\.\//g, '')+'/' : ''
    controlledPaths.Push('./'+prevItem+item)
    return [...memo, './'+prevItem+item]
  }, []).map(dir => {
    fs.mkdir(dir, err => {
      if (err && err.code != 'EEXIST') throw err
      // Delete created directory (or skipped) from controlledPath
      controlledPaths.splice(controlledPaths.indexOf(dir), 1)
      if (controlledPaths.length === 0) {
        return callback()
      }
    })
  })
}

// Usage
mkdirRecursive('./photos/recent', () => {
  console.log('Directories created succesfully!')
})
0
muratgozel

このアプローチはどうでしょうか。

if (!fs.existsSync(pathToFile)) {
            var dirName = "";
            var filePathSplit = pathToFile.split('/');
            for (var index = 0; index < filePathSplit.length; index++) {
                dirName += filePathSplit[index]+'/';
                if (!fs.existsSync(dirName))
                    fs.mkdirSync(dirName);
            }
        }

これは相対パスに対して機能します。

0

これと同じくらいきれい:)

function makedir(fullpath) {
  let destination_split = fullpath.replace('/', '\\').split('\\')
  let path_builder = destination_split[0]
  $.each(destination_split, function (i, path_segment) {
    if (i < 1) return true
    path_builder += '\\' + path_segment
    if (!fs.existsSync(path_builder)) {
      fs.mkdirSync(path_builder)
    }
  })
}
0
Bob Vandevliet