노드의 fs.mkdirSync로 전체 경로를 만드는 방법은 무엇입니까?


159

존재하지 않는 경우 전체 경로를 만들려고합니다.

코드는 다음과 같습니다.

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

이 코드는 하나의 서브 디렉토리 ( 'dir1'과 같은 newDest) 만있는 한 훌륭하게 작동하지만 ( 'dir1 / dir2')와 같은 디렉토리 경로가 있으면 실패합니다. 오류 . ENOENT, 해당 파일 또는 디렉토리 없음

필요에 따라 몇 줄의 코드로 전체 경로를 만들 수 있기를 원합니다.

나는 fs에 재귀 적 옵션이 있으며 이것을 다음과 같이 시도했다.

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

존재하지 않는 디렉토리를 재귀 적으로 만드는 것이 간단해야한다고 생각합니다. 내가 빠진 것이거나 경로를 구문 분석하고 각 디렉토리를 확인하여 존재하지 않는 경우 생성해야합니까?

저는 Node를 처음 접했습니다. 이전 버전의 FS를 사용하고 있습니까?


1
이 Google 검색github.com/substack/node-mkdirp 및 기타 모든 종류의 솔루션 이 있습니다 .
jfriend00

4
@AndyRay이 StackOverflow 질문은 이제이 질문에 대한 구글의 최고 결과입니다. 그것은 재귀임을 의미하기 때문에 재밌습니다 ....
Matt Parkins

1
즉 12 개 + 해결할 수있는 문제를 노드에 문제를 업데이트, 노드의 이전 버전에 문제가 있었다
MrJomp

답변:


48

하나의 옵션은 shelljs 모듈 을 사용하는 것입니다

npm 설치 shelljs

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

해당 페이지에서 :

사용 가능한 옵션 :

p : 전체 경로 (필요한 경우 중간 디렉토리 작성)

다른 사람들이 지적했듯이, 더 집중된 다른 모듈이 있습니다. 그러나 mkdirp 외부에는 다른 유용한 쉘 작업 (예 : grep 등)이 있으며 Windows 및 * nix에서 작동합니다.


2
감사! 나는 exec (나는 이미 이것을 사용하고 있었다)를 사용하여 끝내었고 매력처럼 일했다. var exec = require ( 'child_process'). exec; var command = "mkdir -p '"+ newDest + "'"; var 옵션 = {}; var after = function (error, stdout, stderr) {console.log ( '오류', 오류); console.log ( 'stdout', stdout); console.log ( 'stderr', stderr); } exec (명령, 옵션, 이후);
David Silva Smith

24
이 옵션은 명령 행 mkdir 인스턴스가없는 node.js 플랫폼 (예 : Linux가 아닌 호스트)에서 중단 될 수 있으므로 중요한 경우 이식성이 없습니다.
cshotton

1
@ cshotton-당신은 의견이나 답변을 참조하고 있습니까? shelljs는 Windows에서도 작동합니다. exec mkdir -p (주석)는 물론 아닙니다.
bryanmac

이 멋진 기능 을 Promise 또는 콜백과 함께 사용할 수 있습니다 .
Илья Зеленько

1
이것은 솔루션이 아니며 솔루션의 대안입니다. 문맥 : pics.onsizzle.com/…
Nika Kasradze

413

편집하다

NodeJS 버전은 10.12.0네이티브 지원을 모두 추가했습니다 mkdirmkdirSync함께 재귀 적으로 디렉터리를 만들려면 recursive: true다음과 같은 옵션 :

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

데모

시도 해봐!

설명

  • [업데이트] 이 솔루션은 EISDIRMac EPERMEACCES Windows 용. @PediT., @JohnQ, @ deed02392, @robyoder 및 @Almenon의 모든 의견에 감사드립니다.
  • 이 솔루션은 상대절대를 모두 처리합니다. 경로 경로를 합니다. @john의 의견에 감사드립니다.
  • 상대 경로의 경우, 현재 작업중인 디렉토리에 대상 디렉토리가 작성 (해결)됩니다. 현재 스크립트 디렉토리를 기준으로 해결하려면 다음을 전달하십시오.{isRelativeToScript: true} .
  • 사용 path.seppath.resolve()뿐만 아니라, /크로스 플랫폼 문제를 방지하기 위해 연결.
  • 사용 fs.mkdirSync과 함께 오류 처리 try/catch경쟁 조건을 처리하기 위해 발생하는 경우를 : 다른 프로세스로 호출 사이에 파일을 추가 할 수 있습니다 fs.existsSync()fs.mkdirSync()예외가 발생합니다.
    • 이를 달성하는 다른 방법은 파일이 존재하는지 확인한 다음 파일을 만드는 것 if (!fs.existsSync(curDir) fs.mkdirSync(curDir);입니다. 그러나 이것은 코드를 경쟁 조건에 취약하게 만드는 반 패턴입니다. @GershomMaes 덕분에 디렉토리 존재 점검에 대한 의견이 있습니다.
  • 디스트 럭처링 을 지원하려면 Node v6 이상이 필요합니다 . (이전 노드 버전 으로이 솔루션을 구현하는 데 문제가 있으면 의견을 남겨주세요)

7
추가 라이브러리 나 접근 방식이 필요하지 않은 쉽고 재귀적인 응답을위한 찬성!
MikingTheViking

1
누락 된 require 문 : const fs = require ( 'fs'); const 경로 = require ( 'path');
Christopher Bull

1
@ChristopherBull은 의도적으로 논리에 초점을 맞추기 위해 추가 된 것이 아니라 어쨌든 추가했습니다. 감사합니다;)
Mouneer

1
12 줄의 견고한 코드, 0의 의존성, 매번 가져갈 것입니다.
moodboom

1
Mac OS X 10.12.6의 @Mouneer에서 절대 경로를 전달한 후 "/"를 만들려고 할 때 발생하는 오류는 "EISDIR"입니다 (오류 : EISDIR : mkdir '/'디렉토리에서 잘못된 작업). 아마도 dir 존재를 검사하는 것이 여전히 가장 좋은 크로스 플랫폼 방법입니다 (느리게 될 것임을 인정합니다).
John Q

78

더 강력한 대답은 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'....

전체 라이브러리가 아닌 필요한 것만 가져 오기 때문에이 답변을 선호하십시오
Juan Mendes

1
Populist 배지에서 축하합니다 ;-)
janos

1
감사. 가장 좋은 방법입니다.
스테판 라파엘


48

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


5
이것이 가장 좋은 답변입니다! 우리 대부분은 이미 앱에 fs-extra를 가지고 있습니다.
pagep

memfs단위 테스트 에 사용할 수 있다면 좋을 것 입니다. 그것은 :-( github.com/jprichardson/node-fs-extra/issues/274
schnatterer

31

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

4
답을 할 때 왜 답되는지에 대한 설명을하는 것이 좋습니다 .
Stephen Rauch

죄송합니다, 당신은 바로, 나는 따라이 방법 청소기가 쉽게 생각하는
josebui

4
@josebui 환경 문제를 피하기 위해 슬래시 (/) 대신 "path.sep"를 사용하는 것이 좋습니다.
Arvin

다른 답변과 같이 노드> = 10이 필요하지 않기 때문에 좋은 솔루션
Karim

29

이 기능은 버전 10.12.0에서 node.js에 추가되었으므로 호출에 {recursive: true}두 번째 인수만큼 옵션 을 전달하는 것만 큼 쉽습니다 fs.mkdir(). 공식 문서예를 참조하십시오 .

외부 모듈이나 자체 구현이 필요하지 않습니다.



1
디렉토리가 존재하고 중지되면 오류가 발생합니다. try catch 블록을 사용하면 존재하지 않는 다른 폴더를 계속 만들 수 있습니다.
Choco Li

1
이것이 정답입니다. 디렉토리가 이미 존재하면 발생하지 않으며 fs.promises.mkdir을 통해 async / await와 함께 사용할 수 있습니다.
Rich Apodaca

7

나는 이것이 오래된 질문이라는 것을 알고 있지만 nodejs v10.12.0은 이제 recursive옵션을 true로 설정하여 이것을 기본적으로 지원 합니다. 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;
});


2

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

단순히 경로에 폴더가 있는지 재귀 적으로 확인하고 존재하지 않는지 확인하면서 폴더를 만들 수 있습니다. ( 외부 라이브러리 없음 )

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

2

다음 기능을 사용할 수 있습니다

const recursiveUpload = (경로 : 문자열) => {const 경로 = 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


1

답변이 너무 많지만 경로를 분할 한 다음 왼쪽에서 오른쪽으로 다시 빌드하여 작동하는 재귀없는 솔루션이 있습니다.

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 우리는 노드 fs에 대해 이야기하지 않습니다 .Windows 명령 줄이며 전자는 꽤 용서하며 위의 코드는 간단하게 작동합니다. Windows는 더 완벽한 솔루션 크로스 플랫폼입니다.


윈도우의 파일은 슬래시가 아닌 백 슬래시로 처리됩니다. 코드가 단순히 작동하지 않습니다. C : \ data \ test ...
DDD

수정했지만 댓글의 유효성을 검사 할 것을 제안합니다. 노드에서 다음을 시도하고 어떤 일이 발생하는지 확인 var fs = require ( 'fs') fs.mkdirSync ( 'test') fs.mkdirSync ( 'test \\ test1') fs.mkdirSync ( 'test / test2')
Hamiora

당신이 무슨 말을하든간에, 더 나은 코드를 작성하는 법을 배우기 전까지 내 다운 투표는 계속 유지됩니다.
DDD

ㅋ. 더 나은 코드를 작성하는 방법을 배우기 위해 열심히 노력할 것입니다. OP를 포함한 위의 BTW 답변은 슬래시를 사용합니다. 조업 중지를 제안하십시오.
Hamiora 2016 년

1
path.sep나를 위해 / 또는 \\로오고 있습니다. path.delimiter: 또는;.
조쉬 앤더슨 슬레이트

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

0

디렉토리를 재귀 적으로 생성하는 비동기 방식 :

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

다음 mkdirp은 nodejs 의 필수 버전입니다 .

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

이 방법은 어떻습니까?

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

mouneer의 제로 의존성 답변을 바탕 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);
}

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

fs.mkdir의 재귀 옵션에 문제가 있었으므로 다음을 수행하는 함수를 만들었습니다.

  1. 최종 대상 디렉토리부터 루트 상위까지 모든 디렉토리 목록을 작성합니다.
  2. mkdir 함수가 작동하는 데 필요한 디렉토리의 새 목록을 작성합니다.
  3. 최종 디렉토리를 포함하여 필요한 각 디렉토리를 만듭니다.

    function createDirectoryIfNotExistsRecursive(dirname) {
        return new Promise((resolve, reject) => {
           const fs = require('fs');
    
           var slash = '/';
    
           // backward slashes for windows
           if(require('os').platform() === 'win32') {
              slash = '\\';
           }
           // initialize directories with final directory
           var directories_backwards = [dirname];
           var minimize_dir = dirname;
           while (minimize_dir = minimize_dir.substring(0, minimize_dir.lastIndexOf(slash))) {
              directories_backwards.push(minimize_dir);
           }
    
           var directories_needed = [];
    
           //stop on first directory found
           for(const d in directories_backwards) {
              if(!(fs.existsSync(directories_backwards[d]))) {
                 directories_needed.push(directories_backwards[d]);
              } else {
                 break;
              }
           }
    
           //no directories missing
           if(!directories_needed.length) {
              return resolve();
           }
    
           // make all directories in ascending order
           var directories_forwards = directories_needed.reverse();
    
           for(const d in directories_forwards) {
              fs.mkdirSync(directories_forwards[d]);
           }
    
           return resolve();
        });
     }

-1

Exec은 Windows에서 지저분해질 수 있습니다. 더 "노디"솔루션이 있습니다. 기본적으로 디렉토리가 존재하는지 확인하고 하위 디렉토리가 있거나 하위 디렉토리가 있는지 확인하기 위해 재귀 호출이 있습니다. 다음은 자식을 만들고 완료되면 함수를 호출하는 함수입니다.

fs = require('fs');
makedirs = function(path, func) {
 var pth = path.replace(/['\\]+/g, '/');
 var els = pth.split('/');
 var all = "";
 (function insertOne() {
   var el = els.splice(0, 1)[0];
   if (!fs.existsSync(all + el)) {
    fs.mkdirSync(all + el);
   }
   all += el + "/";
   if (els.length == 0) {
    func();
   } else {
     insertOne();
   }
   })();

}


-1

이 모두를 이해하기 때문에이 버전은 최고 응답보다 윈도우에서 더 잘 작동 /하고 path.sep그래서 슬래시들이 정상적으로 윈도우에서 작동하는지. 절대 및 상대 경로를 지원합니다 (에 상대적 process.cwd).

/**
 * Creates a folder and if necessary, parent folders also. Returns true
 * if any folders were created. Understands both '/' and path.sep as 
 * path separators. Doesn't try to create folders that already exist,
 * which could cause a permissions error. Gracefully handles the race 
 * condition if two processes are creating a folder. Throws on error.
 * @param targetDir Name of folder to create
 */
export function mkdirSyncRecursive(targetDir) {
  if (!fs.existsSync(targetDir)) {
    for (var i = targetDir.length-2; i >= 0; i--) {
      if (targetDir.charAt(i) == '/' || targetDir.charAt(i) == path.sep) {
        mkdirSyncRecursive(targetDir.slice(0, i));
        break;
      }
    }
    try {
      fs.mkdirSync(targetDir);
      return true;
    } catch (err) {
      if (err.code !== 'EEXIST') throw err;
    }
  }
  return false;
}

Windows를 올바르게 지원하는 다운 보트가 있습니까? 다른 OS에서도 작동한다고 언급 했습니까?
Qwertie
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.