Node.js สร้างโฟลเดอร์หรือใช้ที่มีอยู่


186

ฉันมีอ่านเอกสารของ Node.js fs.mkdir()และเว้นแต่ถ้าฉันพลาดบางสิ่งบางอย่างมันไม่ได้บอกสิ่งที่พารามิเตอร์ที่มีในการดำเนินงานบางอย่างโดยเฉพาะอย่างยิ่ง อย่างที่คุณเห็นในเอกสารมันไม่มาก

ปัจจุบันฉันมีรหัสนี้ซึ่งพยายามสร้างโฟลเดอร์หรือใช้ที่มีอยู่แทน:

fs.mkdir(path,function(e){
    if(!e || (e && e.code === 'EEXIST')){
        //do something with contents
    } else {
        //debug
        console.log(e);
    }
});

แต่ฉันสงสัยว่านี่เป็นวิธีที่ถูกต้องหรือไม่ การตรวจสอบรหัสEEXISTเป็นวิธีที่ถูกต้องหรือไม่ที่จะรู้ว่ามีโฟลเดอร์อยู่แล้ว ฉันรู้ว่าฉันสามารถทำfs.stat()ก่อนที่จะสร้างไดเรกทอรี แต่นั่นจะเป็นสองความนิยมต่อระบบไฟล์

ประการที่สองมีเอกสารรายละเอียดที่สมบูรณ์หรืออย่างน้อยของ Node.js ที่มีรายละเอียดเกี่ยวกับวัตถุข้อผิดพลาดที่มีพารามิเตอร์ใดที่มีความหมาย ฯลฯ


31
nitpick ขนาดเล็ก e &&แต่ได้รับการกำจัด หาก!eล้มเหลวคุณก็รู้ว่าeเป็นความจริง
ฉันเกลียด Lazy

คำตอบ:


236

วิธีที่ดีในการทำเช่นนี้คือการใช้โมดูลmkdirp

$ npm install mkdirp

ใช้มันเพื่อเรียกใช้ฟังก์ชันที่ต้องใช้ไดเรกทอรี การโทรกลับถูกเรียกหลังจากสร้างเส้นทางหรือหากเส้นทางนั้นมีอยู่แล้ว ข้อผิดพลาดerrถูกตั้งค่าหาก mkdirp ไม่สามารถสร้างเส้นทางไดเรกทอรี

var mkdirp = require('mkdirp');
mkdirp('/tmp/some/path/foo', function(err) { 

    // path exists unless there was an error

});

3
มันดูเหมือนว่าฉันที่ถูกต้อง (อ่าน 'ไม่พึ่งพาเพิ่ม') คำตอบจะเป็นหนึ่งต่ำลงโดย @Raugaral fs.exists(Sync)ใช้
Ricardo Pedroni

@meawoppl มันคือ 'makedirectory'p ไม่รู้จัก 'p'
andrew

4
@RicardoPedroni วิธีที่ถูกต้องคือการใช้โมดูล โมดูลมักจะพยายามอย่างเต็มที่ที่จะแก้ปัญหาเดียวและมักจะได้รับการบำรุงรักษา คุณสามารถอัพเดทได้อย่างง่ายดายด้วย npm นอกจากนี้คุณควรหลีกเลี่ยงการใช้ fs.exists [Sync] โดยเฉพาะเนื่องจากการใช้งานหมายถึงสภาพการแข่งขัน
1j01

16
@ 1j01 ฉันไม่เชื่อว่าวิธีที่ถูกต้องคือการใช้โมดูลหากแพลตฟอร์มสนับสนุนการดำเนินการตามปกติ นั่นเป็นถนนสู่ความโกลาหล ฉันต้องยอมรับว่ามีคำตอบที่ดีกว่าจากมุมมองทางเทคนิค
c ..

2
@ 1j01 การใช้งานการทำข้อมูลให้ตรงกันนั้นบ่งบอกถึงสภาพการแข่งขันเพราะการใช้งานนั้นมีความละเอียดสำหรับพวกเขา
c ..

193

แก้ไข: เนื่องจากคำตอบนี้ได้รับความนิยมมากฉันได้อัปเดตเพื่อให้สอดคล้องกับแนวปฏิบัติที่ทันสมัย

โหนด> = 10

{ recursive: true }ตัวเลือกใหม่ของโหนดfsตอนนี้อนุญาตให้กำเนิด mkdir -pตัวเลือกนี้จะเลียนแบบพฤติกรรมของยูนิกซ์ของ มันจะตรวจสอบให้แน่ใจซ้ำ ๆ ว่าทุกส่วนของเส้นทางมีอยู่แล้วและจะไม่โยนข้อผิดพลาดหากมีส่วนใดส่วนหนึ่งอยู่

(หมายเหตุ: มันอาจยังคงโยนข้อผิดพลาดเช่นEPERMหรือEACCESSดังนั้นยังดีกว่าห่อในtry {} catch (e) {}ถ้าการใช้งานของคุณไวต่อมัน)

รุ่นซิงโครนัส

fs.mkdirSync(dirpath, { recursive: true })

เวอร์ชัน Async

await fs.promises.mkdir(dirpath, { recursive: true })

รุ่นโหนดที่เก่ากว่า

ใช้ a try {} catch (err) {}คุณสามารถบรรลุผลอย่างงดงามได้โดยไม่ต้องเผชิญกับสภาพการแข่งขัน

เพื่อป้องกันการเสียเวลาระหว่างการตรวจสอบการมีอยู่และการสร้างไดเรกทอรีเราเพียงแค่พยายามสร้างมันขึ้นมาตรงๆและไม่สนใจข้อผิดพลาดหากเป็นEEXIST(มีไดเรกทอรีอยู่แล้ว)

อย่างไรก็ตามหากข้อผิดพลาดไม่ได้EEXISTเราควรจะโยนข้อผิดพลาดเพราะเราสามารถจัดการกับบางสิ่งบางอย่างเช่นEPERMหรือEACCES

function ensureDirSync (dirpath) {
  try {
    return fs.mkdirSync(dirpath)
  } catch (err) {
    if (err.code !== 'EEXIST') throw err
  }
}

สำหรับmkdir -pเหมือนพฤติกรรม recursive เช่น./a/b/cคุณต้องการมีที่จะเรียกมันในทุกส่วนของ dirpath เช่น./a, ./a/b,.a/b/c


var fs = Npm.require ('fs'); var dir = process.env.PWD + '/ files / users /' + this.userId + '/'; ลอง {fs.mkdirSync (dir); } catch (e) {if (e.code! = 'EEXIST') ส่ง e; }
Aaron

ฉันลองใช้รหัสของคุณสร้าง js-script ที่ใช้การสร้างแคตตาล็อกเช่นนี้: mkdirpSync (path.join (__ dirname, 'first', 'second', 'second', 'third', 'ololol', 'works')); แต่ได้รับข้อผิดพลาดนี้: $ node 1.js fs.js: 747 return binding.mkdir (pathModule._makeLong (path), ^ Error: EPERM การดำเนินการไม่ได้รับอนุญาต 'C: \' ที่ Error (native) ที่ Object.fs mkdirSync (fs.js: 747: 18) ที่ mkdirpSync (C: \ Users \ MAXIM \ Desktop \ test \ 1.js: 15: 8) ที่วัตถุ <anonymous> (C: \ Users \ MAXIM \ Desktop \ test \ 1.js: 19: 1) ... คุณสามารถแนะนำสิ่งที่อาจจะผิดที่ใช้บนหน้าต่างเห็นได้ชัด :)?
Alendorff

EPERM ดูเหมือนจะเป็นปัญหาการอนุญาตดังนั้นสคริปต์จะไม่สามารถใช้งานได้อีกต่อไป
Christophe Marois

ฉันคิดว่ามันจะดีกว่า: var mkdirpSync = function (dirpath) {var parts = dirpath.split (path.sep); สำหรับ (var i = 1; i <= parts.length; i ++) {ลอง {fs.mkdirSync (path.join.apply (null, parts.slice (0, i))); } catch (ข้อผิดพลาด) {ถ้า (error.code! = 'EEXIST') {ส่งข้อผิดพลาด; }}}}
Manish

1
คำเตือน: มันไม่ทำงานหากเส้นทางของคุณเริ่มต้นด้วย /
acemtp

62

หากคุณต้องการซับที่รวดเร็วและสกปรกให้ใช้:

fs.existsSync("directory") || fs.mkdirSync("directory");

1
fs.existsเลิกใช้แล้ว: nodejs.org/api/fs.html#fs_fs_exists_path_callback
adius

7
fs.existsSync (... ) ไม่ได้คัดค้านดังนั้นคำตอบนี้ดูเหมือนจะใช้ได้
Dan Haywood

หัวขึ้น! จะไม่ทำงานสำหรับ "dir / foo / บาร์" คือขาด mkdir -p คุณลักษณะธง
คาร์ลหลอกลวง

นอกจากนี้ยังมีเงื่อนไขการแข่งขัน
Evert

26

Node.js เอกสารสำหรับพื้นเลื่อนไปยังหน้าคนสำหรับลินุกซ์fs.mkdir mkdir(2)นั่นหมายความว่าEEXISTจะมีการระบุหากเส้นทางนั้นมีอยู่ แต่ไม่ใช่ไดเรกทอรีที่สร้างกรณีมุมที่ไม่สะดวกถ้าคุณไปเส้นทางนี้

คุณอาจจะดีกว่าการโทรfs.statซึ่งจะบอกคุณว่าเส้นทางนั้นมีอยู่หรือไม่และเป็นไดเรกทอรีในการโทรครั้งเดียว สำหรับ (สิ่งที่ฉันสมมติคือ) กรณีปกติที่มีไดเรกทอรีอยู่แล้วมันเป็นเพียงระบบไฟล์เดียว

fsวิธีการโมดูลเหล่านี้เป็น wrappers รอบ ๆ C APIs ดั้งเดิมดังนั้นคุณต้องตรวจสอบ man pages ที่อ้างอิงใน node.js docs สำหรับรายละเอียด


19
การโทรstatมาก่อนmkdirมีศักยภาพในการแข่งขัน - จำไว้ในใจ
Roger Lipscombe

24

คุณสามารถใช้สิ่งนี้:

if(!fs.existsSync("directory")){
    fs.mkdirSync("directory", 0766, function(err){
        if(err){
            console.log(err);
            // echo the result back
            response.send("ERROR! Can't make the directory! \n");
        }
    });
}

1
-1 ฉันไม่เชื่อว่างานนี้statSyncจะเกิดข้อผิดพลาดหากไม่มีเอนทิตีเลยทำให้รหัสขัดข้อง คุณต้องปิดสิ่งนี้ในtry/catchบล็อก
Chris Foster

2
ขออภัยฉันผิด เปลี่ยน "statSync" สำหรับ "existSync"
Raugaral

5
ตามnodejs.org/api/fs.html#fs_fs_mkdirsync_path_modeตัวแปร Sync ของ mkdir ไม่ยอมรับการโทรกลับ
danwellman

1
ตามnodejs.org/api/fs.html#fs_fs_existssync_path , fs.existsSync()และfs.exists()จะเลิกใช้
pau.moreno

7

ฉันเสนอวิธีแก้ปัญหาโดยไม่มีโมดูล (ไม่แนะนำให้สะสมโมดูลเพื่อการบำรุงรักษาโดยเฉพาะอย่างยิ่งสำหรับฟังก์ชั่นขนาดเล็กที่สามารถเขียนในสองสามบรรทัด ... ):

การปรับปรุงครั้งล่าสุด :

ใน v10.12.0 ตัวเลือกการเรียกซ้ำ NodeJS ที่ไม่สมบูรณ์:

// Create recursive folder
fs.mkdir('my/new/folder/create', { recursive: true }, (err) => { if (err) throw err; });

อัปเดต:

// Get modules node
const fs   = require('fs');
const path = require('path');

// Create 
function mkdirpath(dirPath)
{
    if(!fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK))
    {
        try
        {
            fs.mkdirSync(dirPath);
        }
        catch(e)
        {
            mkdirpath(path.dirname(dirPath));
            mkdirpath(dirPath);
        }
    }
}

// Create folder path
mkdirpath('my/new/folder/create');

fs.exists()ถูกเลิกใช้ในโหนด v9 ใช้fs.access()แทน (ส่งคืนundefinedหากไฟล์มีอยู่มิฉะนั้นจะเกิดข้อผิดพลาดENOENT)
chharvey

หากไม่มีแพ็กเกจ npm ใด ๆ ก็ใช้งานได้ มันเป็นรหัสที่มีค่า ขอบคุณ
Karthik Sridharan

อันนี้ค่อนข้างดีสำหรับการสร้างโฟลเดอร์ภายใต้เส้นทางยาวที่มีอยู่;) ขอบคุณผู้ชาย
Tsung Goh

1
เกี่ยวกับfs.mkdirSync('my/new/folder/create', {recursive: true})อะไร
saitho

ขอบคุณมาก! ฉันอัปเดตโพสต์ของฉันเพื่อช่วยเหลือผู้อื่น โหนด 10.12.0 ล่าสุดเกินไป
Liberateur

4

คุณยังสามารถใช้fs-extraซึ่งให้การดำเนินงานไฟล์ที่ใช้บ่อยมาก

รหัสตัวอย่าง:

var fs = require('fs-extra')

fs.mkdirs('/tmp/some/long/path/that/prob/doesnt/exist', function (err) {
  if (err) return console.error(err)
  console.log("success!")
})

fs.mkdirsSync('/tmp/another/path')

เอกสารที่นี่: https://github.com/jprichardson/node-fs-extra#mkdirsdir-callback


4

นี่คือรหัส ES6 ที่ฉันใช้เพื่อสร้างไดเรกทอรี (เมื่อไม่มี):

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

function createDirectory(directoryPath) {
  const directory = path.normalize(directoryPath);

  return new Promise((resolve, reject) => {
    fs.stat(directory, (error) => {
      if (error) {
        if (error.code === 'ENOENT') {
          fs.mkdir(directory, (error) => {
            if (error) {
              reject(error);
            } else {
              resolve(directory);
            }
          });
        } else {
          reject(error);
        }
      } else {
        resolve(directory);
      }
    });
  });
}

const directoryPath = `${__dirname}/test`;

createDirectory(directoryPath).then((path) => {
  console.log(`Successfully created directory: '${path}'`);
}).catch((error) => {
  console.log(`Problem creating directory: ${error.message}`)
});

บันทึก:

  • ในการเริ่มต้นของcreateDirectoryฟังก์ชั่นฉันปรับเส้นทางให้เป็นมาตรฐานเพื่อให้แน่ใจว่าจะใช้ชนิดตัวแยกเส้นทางของระบบปฏิบัติการอย่างสม่ำเสมอ (เช่นนี้จะกลายC:\directory/testเป็นC:\directory\test(เมื่ออยู่บน Windows)
  • fs.existsจะเลิกว่าทำไมฉันจะใช้fs.statเพื่อตรวจสอบว่าไดเรกทอรีที่มีอยู่แล้ว
  • หากไม่มีไดเรกทอรีรหัสข้อผิดพลาดจะเป็นENOENT( E rror NO ENT ry)
  • ไดเรกทอรีจะถูกสร้างขึ้นโดยใช้ fs.mkdir
  • ฉันชอบฟังก์ชั่นแบบอะซิงโครนัสfs.mkdirมากกว่าการปิดกั้นคู่fs.mkdirSyncและเนื่องจากการห่อPromiseนั้นจะรับประกันได้ว่าเส้นทางของไดเรกทอรีจะถูกส่งกลับหลังจากสร้างไดเรกทอรีสำเร็จแล้ว

ขอบคุณสำหรับการแก้ปัญหาที่ไม่เกี่ยวข้องกับโมดูลที่ไม่จำเป็น มันทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน ฉันหวังว่าจะมีคำตอบเพิ่มเติมเช่นนี้!
Ken Lyon

3

คุณควรที่จะไม่นับจำนวนระบบไฟล์ที่นิยมในขณะที่คุณโค้ดใน Javascript ในความคิดของฉัน อย่างไรก็ตาม (1) stat& mkdirและ (2) mkdirและตรวจสอบ (หรือทิ้ง) รหัสข้อผิดพลาดทั้งสองวิธีเป็นวิธีที่ถูกต้องในการทำสิ่งที่คุณต้องการ


-1 ฉันไม่เห็นว่าการตรวจสอบหรือการละทิ้งทั้งคู่อาจเป็นวิธีที่ถูกต้องในการทำเช่นนั้น นี่ไม่ใช่คำตอบที่ค่อนข้างสวย
Matt Ball

เป็นวิธีที่ดีในการ mkdir ไดเรกทอรีหรือใช้ที่มีอยู่ ฉันไม่เห็นว่าทำไมคุณไม่เห็น การตรวจสอบรหัสข้อผิดพลาดนั้นเป็นสิ่งที่ดีในขณะที่การทิ้งรหัสข้อผิดพลาดนั้นเป็นสิ่งที่ดี คุณไม่เห็นด้วยหรือ
Chul-Woong Yang

1
บางทีนี่อาจเป็นปัญหาเรื่องภาษา แต่ฉันอ่านเพราะไม่ตอบคำถามที่ OP ถาม
แมตต์บอล

ฉันเห็นสิ่งที่เป็นจุดของคุณ อย่างไรก็ตามฉันเชื่อว่ามีหลายวิธีที่จะทำสิ่งที่ถูกต้อง ขอบคุณ
Chul-Woong Yang

2

สร้างไดเรกทอรีชื่อแบบไดนามิกสำหรับผู้ใช้แต่ละคน ... ใช้รหัสนี้

***suppose email contain user mail address***

var filessystem = require('fs');
var dir = './public/uploads/'+email;

if (!filessystem.existsSync(dir)){
  filessystem.mkdirSync(dir);

}else
{
    console.log("Directory already exist");
}

1

คุณสามารถทำสิ่งนี้ได้ทั้งหมดด้วยโมดูลระบบไฟล์

const
  fs = require('fs'),
  dirPath = `path/to/dir`

// Check if directory exists.
fs.access(dirPath, fs.constants.F_OK, (err)=>{
  if (err){
    // Create directory if directory does not exist.
    fs.mkdir(dirPath, {recursive:true}, (err)=>{
      if (err) console.log(`Error creating directory: ${err}`)
      else console.log('Directory created successfully.')
    })
  }
  // Directory now exists.
})

คุณไม่จำเป็นต้องตรวจสอบว่ามีไดเรกทอรีอยู่หรือไม่ รหัสต่อไปนี้ยังรับประกันว่าไดเรกทอรีนั้นมีอยู่แล้วหรือถูกสร้างขึ้น

const
  fs = require('fs'),
  dirPath = `path/to/dir`

// Create directory if directory does not exist.
fs.mkdir(dirPath, {recursive:true}, (err)=>{
  if (err) console.log(`Error creating directory: ${err}`)
  // Directory now exists.
})

0

คำตอบของ Raugaralแต่ด้วยฟังก์ชั่น -p น่าเกลียด แต่ใช้งานได้:

function mkdirp(dir) {
    let dirs = dir.split(/\\/).filter(asdf => !asdf.match(/^\s*$/))
    let fullpath = ''

    // Production directory will begin \\, test is on my local drive.
    if (dirs[0].match(/C:/i)) {
        fullpath = dirs[0] + '\\'
    }
    else {
        fullpath = '\\\\' + dirs[0] + '\\'
    }

    // Start from root directory + 1, build out one level at a time.
    dirs.slice(1).map(asdf => {
        fullpath += asdf + '\\'
        if (!fs.existsSync(fullpath)) {
            fs.mkdirSync(fullpath)
        }
    })
}//mkdirp

0

ทางเลือกใหม่สำหรับคำตอบของ Teemu Ikonenซึ่งง่ายและอ่านง่ายคือใช้ensureDirวิธีการของfs-extraแพ็คเกจ

ไม่เพียง แต่จะสามารถใช้แทนการโจ่งแจ้งสำหรับfsโมดูลในตัว แต่ยังมีฟังก์ชั่นอื่น ๆ อีกมากมายนอกเหนือไปจากฟังก์ชั่นการใช้งานของfsแพ็คเกจ

ensureDirวิธีเป็นชื่อแนะนำเพื่อให้แน่ใจว่าไดเรกทอรีที่มีอยู่ หากโครงสร้างไดเรกทอรีไม่มีอยู่มันจะถูกสร้างขึ้น กดmkdir -pไลค์ ไม่ใช่เพียงแค่โฟลเดอร์ปลายทาง แต่จะสร้างเส้นทางทั้งหมดแทนหากไม่มีอยู่แล้ว

หนึ่งที่ระบุไว้ข้างต้นเป็นasyncรุ่นของมัน นอกจากนี้ยังมีวิธีการซิงโครนัสเพื่อดำเนินการนี้ในรูปแบบของensureDirSyncวิธีการ


0

@ คำตอบของ Liberateur ข้างต้นไม่ได้ผลสำหรับฉัน (Node v8.10.0) การดัดแปลงเล็กน้อยทำไปได้ แต่ฉันไม่แน่ใจว่านี่เป็นวิธีที่ถูกต้องหรือไม่ กรุณาแนะนำ

// Get modules node
const fs   = require('fs');
const path = require('path');

// Create
function mkdirpath(dirPath)
{
    try {
        fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
    }
    catch(err) {
        try
        {
            fs.mkdirSync(dirPath);
        }
        catch(e)
        {
            mkdirpath(path.dirname(dirPath));
            mkdirpath(dirPath);
        }
    }
}

// Create folder path
mkdirpath('my/new/folder/create');
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.