codememo

Node.js를 사용하여 디렉터리가 없는 경우 디렉터리를 만드는 방법

tipmemo 2023. 5. 28. 20:48
반응형

Node.js를 사용하여 디렉터리가 없는 경우 디렉터리를 만드는 방법

디렉토리가 존재하지 않는 경우 다음과 같은 방법으로 디렉토리를 작성할 수 있습니까?

스크립트에 대한 전체 권한이 있어야 하며 다른 사용자가 읽을 수 있어야 합니다.

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

개별 dir의 경우:

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

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

또는 중첩된 dir의 경우:

var fs = require('fs');
var dir = './tmp/but/then/nested';

if (!fs.existsSync(dir)){
    fs.mkdirSync(dir, { recursive: true });
}

아니요, 여러 가지 이유로.

  1. 모듈에 다음이 없습니다.exists/existsSync방법.모듈에 있습니다. (아마도 방금 질문에 오타가 났나요?)

  2. 설명서에 명시된 대로 사용할 수 없습니다.exists.

    fs.exists()시대착오적이고 역사적인 이유만으로 존재합니다.당신 자신의 코드에서 그것을 사용할 이유가 거의 없어야 합니다.

    을 열기 입니다. 를 수행하면 에 대한 될 수 . 다른 프로세스는 호출 사이에 파일을 제거할 수 있습니다.fs.exists()그리고.fs.open()파일을 열고 오류가 없을 때 처리하기만 하면 됩니다.

    이 아닌 하고 있기 에, 이 파이아디대있때문에,기고하당전해다의것니합미을한다는야화를무조건일신이이은언조닌에리야렉기해터이▁un▁rather▁since다▁just▁youcondition▁should▁thisally▁implies▁call의▁advice니합▁directory미,것파을일▁we▁a'▁file라고 불러야 한다는 것을 암시합니다.mkdirEEXIST.

  3. 을 나타내는 *어려움을 나타내는 *어려움 *어려움을 .Sync을 수행할 수 디스크로 이동하는 동안 프로그램에서 다른 작업을 수행할 수 없습니다.이 작업은 매우 비용이 많이 드는 작업이며, 이 작업에 걸리는 시간은 노드의 이벤트 루프에 대한 핵심 가정을 깨뜨립니다.

    Sync메소드는 일반적으로 단일 목적의 빠른 스크립트(한 가지 작업을 수행한 후 종료하는 메소드)에서는 괜찮지만 서버를 작성할 때는 거의 사용하지 않아야 합니다. 서버는 I/O 요청 전체 기간 동안 다른 사용자에게 응답할 수 없습니다.여러 클라이언트 요청에 I/O 작업이 필요한 경우 서버가 매우 빠르게 중단됩니다.


    내가 유일하게 사용을 고려한 시간은Sync서버 응용프로그램의 메서드는 시작 시 한 번(그리고 한 번만) 발생하는 작업에 있습니다.예를들면,require 모듈을 로드하는 데 실제로 사용합니다.

    그럼에도 불구하고 많은 동기식 I/O는 서버 시작 시간을 불필요하게 지연시킬 수 있으므로 주의해야 합니다.


    대신 비동기 I/O 방법을 사용해야 합니다.

그래서 우리가 그 조언들을 종합하면, 우리는 다음과 같은 것을 얻을 수 있습니다.

function ensureExists(path, mask, cb) {
    if (typeof mask == 'function') { // Allow the `mask` parameter to be optional
        cb = mask;
        mask = 0o744;
    }
    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', 0o744, function(err) {
    if (err) // Handle folder creation error
    else // We're all good
});

물론, 이것은 다음과 같은 에지 사례를 설명하지 않습니다.

  • 프로그램이 실행되는 동안 폴더가 삭제되면 어떻게 됩니까?(시작하는 동안 한 번만 존재하는지 확인하는 경우)
  • 폴더가 이미 있지만 잘못된 권한을 가진 경우 어떻게 됩니까?

mkdir메서드는 존재하지 않는 디렉터리를 경로에 재귀적으로 생성하고 존재하지 않는 디렉터리는 무시할 수 있습니다.

Node.js 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모듈 먼저.

다음은 네이티브 ECMA스크립트 모듈(플래그 사용 및 .mjs 확장)을 활용하고 루트가 아닌 경로를 처리하며 전체 경로 이름을 설명하는 좀 더 강력한 예입니다.

import fs from 'fs';
import path from 'path';

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

물론 디렉터리가 생성될 때 파일 생성을 보다 읽기 쉬운 동기식 방식으로 활용하기 위해 비동기/대기 기능이 포함된 약속을 사용함으로써 더욱 화려해지고 싶겠지만, 이는 질문의 범위를 벗어난 것입니다.

fs-extra 패키지를 사용하면 한 줄로 다음 작업을 수행할 수 있습니다.

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

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

나는 이것을 위해 매력적으로 작동하는 npm 모듈을 찾았습니다.

재귀적인 행동을 할 뿐입니다.mkdir필요할 때, 예를 들어, "dir-p"와 같이.

한 줄 버전:

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

해결책들

  1. 커먼JS
const fs = require('fs');
const path = require('path');

const dir = path.resolve(path.join(__dirname, 'upload');

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

// OR
if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir, {
    mode: 0o744, // Not supported on Windows. Default: 0o777
  });
}

  1. ESM

를 합니다.package.json config 파일

{
  // declare using ECMAScript modules(ESM)
  "type": "module",
  //...
}
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

// create one custom `__dirname`, because it does not exist in es-module env ⚠️
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const dir = path.resolve(path.join(__dirname, 'upload');

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

// OR
if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir, {
    mode: 0o744, // Not supported on Windows. Default: 0o777
  });
}

2022년 업데이트

import { existsSync } from 'node:fs';

참조

노드 JS 버전: v18.2.0

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

https://nodejs.org/api/fs.html#fsmkdirsyncpath-options

https://nodejs.org/api/url.html#urlfileurltopathurl

https://github.com/nodejs/help/issues/2907#issuecomment-757446568

ESM: ECMA스크립트 모듈

https://nodejs.org/api/esm.html#introduction

그냥 사용할 수 있습니다.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. 다음과 같은 약속 방법을 직접 만들 수 있습니다. (테스트되지 않음):

    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, 유용한 것들을 많이 추가합니다)

한 줄 솔루션:디렉토리가 없는 경우 디렉토리를 작성합니다.

// import
const fs = require('fs')  // In JavaScript
import * as fs from "fs"  // in TypeScript
import fs from "fs"       // in Typescript

// Use
!fs.existsSync(`./assets/`) && fs.mkdirSync(`./assets/`, { recursive: true })

가장 좋은 해결책은 node-fs-extra라는 npm 모듈을 사용하는 것입니다.라고 불리는 방법이 있습니다.mkdir그러면 사용자가 언급한 디렉터리가 만들어집니다.긴 디렉토리 경로를 지정하면 상위 폴더가 자동으로 작성됩니다.모듈은 npm 모듈의 슈퍼셋입니다.fs은 의모기사수있다습니의 할 수 있습니다.fs또한 이 모듈을 추가하는 경우에도 마찬가지입니다.

노드 v10 이상에 대한 간단하고 현대적인 답변

했듯이, 은 부답변부지적일이노터 10사수있다습니용할을 사용할 수 .recursive:true위해서mkdir

아직 지적되지 않은 것은 recursive:true를 사용할 디렉터리가 이미 존재하는 경우 mkdir가 오류를 반환하지 않는다는 것입니다.

따라서 다음을 수행할 수 있습니다.

fsNative.mkdir(dirPath,{recursive:true},(err) => {
    if(err) {
        //note: this does NOT get triggered if the directory already existed
        console.warn(err)
    }
    else{
        //directory now exists 
    }
})

약속 사용하기

또한 노드 10부터 다음을 요구하여 모든 fs 함수의 Promise 버전을 얻을 수 있습니다.fs/promises

이 두 가지를 결합하면 다음과 같은 간단한 해결책을 얻을 수 있습니다.

import * as fs from 'fs/promises';

await fs.mkdir(dirPath, {recursive:true}).catch((err) => {
    //decide what you want to do if this failed
    console.error(err);
});

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

사용:

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

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

fs.vmdk는 더 이상 사용되지 않습니다.그래서 저는 fs.stat()을 사용하여 디렉토리 상태를 확인했습니다.디렉터리가 없는 경우 fs.stat()는 'no such file or directory'와 같은 메시지와 함께 오류를 발생시킵니다.그런 다음 디렉토리를 작성했습니다.

const fs = require('fs').promises;

const dir = './dir';
fs.stat(dir).catch(async (err) => {
  if (err.message.includes('no such file or directory')) {
    await fs.mkdir(dir);
  }
});

Node.js 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;
    }
  }
})();

josh3736의 답변에 TypeScript Promise 리팩터를 추가하고 싶습니다.

동일한 작업을 수행하고 모서리 케이스가 동일합니다.Promise, TypeScript typedefs를 사용할 수 있으며 "using 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
                }
            });
    });
}

하위 디렉터리가 없으면 하위 디렉터리를 만들어야 했습니다.사용한 항목:

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

function ensureDirectoryExists(p) {
    //console.log(ensureDirectoryExists.name, {p});
    const d = path.dirname(p);
    if (d && d !== p) {
        ensureDirectoryExists(d);
    }
    if (!fs.existsSync(d)) {
        fs.mkdirSync(d);
    }
}

Node.js File System 명령 fs.stat을 사용하여 디렉토리가 존재하는지 확인하고 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);
        }
    });
};

설명서에서 비동기식(재귀적)으로 수행하는 방법은 다음과 같습니다.

const fs = require('fs');
const fsPromises = fs.promises;

fsPromises.access(dir, fs.constants.F_OK)
   .catch(async() => {
                await fs.mkdir(dir, { recursive: true }, function(err) {
                    if (err) {
                      console.log(err)
                    }
                  })
    });

다음은 디렉터리를 재귀적으로 만드는 작은 함수입니다.

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

나의 해결책

  1. 커먼JS

var fs = require("fs");

var dir = __dirname + '/upload';

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

if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir, {
    mode: 0o744,
  });
  // mode's default value is 0o744
}

  1. ESM

갱다하package.json 파일

{
  //...
  "type": "module",
  //...
}
import fs from "fs";
import path from "path";

// create one custom `__dirname`, because it not exist in es-module env ⚠️
const __dirname = path.resolve();

const dir = __dirname + '/upload';

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

// OR
if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir, {
    mode: 0o744,
  });
  // mode's default value is 0o744
}

참조

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

https://github.com/nodejs/help/issues/2907#issuecomment-671782092

비동기 / 대기 사용:

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

비동기적으로 이를 수행하는 기능(지금은 찾을 수 없는 동기화 기능을 사용한 SO의 유사한 답변에서 조정됨)

// ensure-directory.js
import { mkdir, access } from 'fs'

/**
 * directoryPath is a path to a directory (no trailing file!)
 */
export default async directoryPath => {
  directoryPath = directoryPath.replace(/\\/g, '/')

  // -- preparation to allow absolute paths as well
  let root = ''
  if (directoryPath[0] === '/') {
    root = '/'
    directoryPath = directoryPath.slice(1)
  } else if (directoryPath[1] === ':') {
    root = directoryPath.slice(0, 3) // c:\
    directoryPath = directoryPath.slice(3)
  }

  // -- create folders all the way down
  const folders = directoryPath.split('/')
  let folderPath = `${root}`
  for (const folder of folders) {
    folderPath = `${folderPath}${folder}/`

    const folderExists = await new Promise(resolve =>
      access(folderPath, error => {
        if (error) {
          resolve(false)
        }
        resolve(true)
      })
    )

    if (!folderExists) {
      await new Promise((resolve, reject) =>
        mkdir(folderPath, error => {
          if (error) {
            reject('Error creating folderPath')
          }
          resolve(folderPath)
        })
      )
    }
  }
}

2023년에 이것을 찾는 다른 사람들은 이제 비동기/대기 - try/catch 구문으로 이것을 수행할 수 있습니다.

import { stat, mkdir } from 'node:fs/promises';

const checkAndMakeDirectory = async (dir) => {
  try {
    await stat(dir);
  } catch (error) {
    if (error.code === "ENOENT") {
      try {
        await mkdir(dir);
      } catch (err) {
        console.error(err.message);
      }
    }
  }
}

언급URL : https://stackoverflow.com/questions/21194934/how-to-create-a-directory-if-it-doesnt-exist-using-node-js

반응형