Node.js를 사용하여 디렉토리가 존재하지 않는 경우 디렉토리를 작성하는 방법은 무엇입니까?


655

디렉토리가없는 경우이를 작성하는 올바른 방법입니까? 스크립트에 대한 모든 권한이 있어야하며 다른 사람이 읽을 수 있어야합니다.

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

답변:


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

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

28
앱 부팅 또는 초기화 에서이 작업을 수행하는 경우 비동기 작업을 수행하는 경우 동일한 작업을 수행하므로 실행을 차단하는 것이 좋습니다. 반복 작업으로 디렉토리를 작성하는 경우 나쁜 습관이지만 성능 문제는 발생하지 않지만 나쁜 습관은 전혀 없습니다. 앱을 부팅하거나 한 번만 작업하는 경우에만 사용하십시오.
tsturzl

20
existSync ()는 더 이상 사용되지 않으며, exist ()는 사용되지 않습니다.- nodejs.org
Ian Chadwick

* Sync메소드를 사용 하는 것은 일반적으로 아니오입니다 : 이벤트 루프를 차단하고 싶지 않습니다
Max Heiber

14
동기화 방법을 사용하면 로컬 스크립트에 적합하며 서버에는 적합하지 않습니다.
부두

해당 블록이 setTimeout으로 둘러싸여 있으면 비동기입니다 .......
Bryan Grace

185

아니요, 여러 가지 이유가 있습니다.

  1. path모듈은 없습니다 exists/ existsSync방법. 그것은에있는 fs모듈. (아마도 질문에 오타가 있었습니까?)

  2. 문서는 명시 적으로 권장하지 않습니다 사용에서 당신을 exists.

    fs.exists()은 시대 주의적이며 역사적 이유로 만 존재합니다. 자신의 코드에서 사용할 이유가 거의 없습니다.

    다른 프로세스가 호출 사이의 파일을 제거 할 수있다 : 특히, 파일을 열기 전에 존재하는 경우는 잎 당신이 취약 경쟁 조건에 대한 안티 패턴 확인 fs.exists()하고 fs.open(). 파일을 열고없는 경우 오류를 처리하십시오.

    우리는 파일이 아닌 디렉토리에 대해 이야기하고 있기 때문에이 조언은 무조건 호출 mkdir하고 무시 해야 함을 의미합니다 EEXIST.

  3. 일반적으로 * Sync메소드 는 피해야합니다 . 차단 중이므로 디스크로 이동하는 동안 프로그램에서 다른 어떤 것도 발생할 수 없습니다. 이것은 매우 비용이 많이 드는 작업이며 시간이 걸리므로 노드의 이벤트 루프에 대한 핵심 가정이 깨집니다.

    * Sync방법은 보통 단일 목적의 빠른 스크립트 (한 가지 작업을 수행 한 다음 종료하는 스크립트)에서 적합하지만 서버를 작성할 때는 거의 사용하지 않아야합니다. 서버는 전체 기간 동안 누군가에게 응답 할 수 없습니다. I / O 요청 중 여러 클라이언트 요청에 I / O 작업이 필요한 경우 서버가 매우 빨리 중단됩니다.


    Sync서버 응용 프로그램에서 * 메서드를 사용하는 유일한 방법 은 시작할 때 한 번만 수행되는 작업입니다 . 예를 들어 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 진 리터럴은 엄격 모드에서 허용되지 않습니까?
Whisher

8
십진수로 씁니다. 0744 == 484.
josh3736


이 "마스크"플래그가 2019 년에도 여전히 관련이 있습니까? 그것의 목적은 무엇입니까?
oldboy

그것은이다 유닉스 파일 모드 - 디렉토리의 읽기 / 쓰기 권한을 설정합니다.
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

29

한 줄 버전에 관심이있는 사람을 위해. :)

//or in typescript: import * as fs from 'fs';
const fs = require('fs');
!fs.existsSync(dir) && fs.mkdirSync(dir);

1 라이너는 실제로 1 라인이 아니라고 주장됩니다.
하이브리드 웹 개발자

20

mkdir폴더가 존재하면 오류를 사용 하고 잡을 수 있습니다 .
이것은 비동기 적이므로 최상의 방법입니다.

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

(선택적으로 모드와 함께 두 번째 인수를 추가하십시오.)


다른 생각들:

  1. 그런 다음 네이티브 약속 을 사용하여 기다리거나 기다릴 수 있습니다 .

    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. 당신은 (unested)와 같은 자신의 약속 방법을 만들 수 있습니다 :

    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()감가 상각 되었다는 리소스에 대한 링크를 추가 할 수 있습니까?
프랜시스

1
코드 전용 답변은 앞으로이 질문을하는 사용자에게는 큰 도움이되지 않습니다. 코드가 원래 문제를 해결하는 이유를 설명하기 위해 답을 편집하십시오
yivi

3
흠, @francis, 나는, Node.js를 v5에보고 있었다 nodejs.org/docs/latest-v5.x/api/fs.html#fs_fs_existssync_path
Ping.Goblue

1
감사! 이 기능은 버전 0.12에 존재하고, 버전 4와 5에서 더 이상 사용되지 않으며, 버전 6과 7에서 복원 된 것 같습니다 ... 좀비 함수의 종류 ...
francis

1
예, 분명히 현재 사용 되지 않습니다 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");
    }

이것은 당신을 도울 수 있습니다 :)


5

중요 : 그러한 파일이나 디렉토리가 없습니다.

해결책

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 's answer의 Typescript Promise 리 팩터를 추가하고 싶습니다 .

그것은 똑같은 일을하고 가장자리가 똑같습니다. 약속을 사용하고 typescript typedef를 사용하고 "엄격한 사용"으로 작동합니다.

// 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

다음 예제와 같이 node File System 명령 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.