Node.js tạo thư mục hoặc sử dụng hiện có


186

Tôi đã đọc tài liệu của Node.js và, trừ khi tôi bỏ lỡ điều gì đó, cụ thể là nó không cho biết các tham số có trong các hoạt động nhất định, cụ thể là gì fs.mkdir(). Như bạn có thể thấy trong tài liệu, nó không nhiều lắm.

Hiện tại, tôi có mã này, nó cố gắng tạo một thư mục hoặc sử dụng một thư mục hiện có thay thế:

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

Nhưng tôi tự hỏi liệu đây có phải là cách đúng đắn để làm điều đó? Kiểm tra mã có EEXISTđúng cách để biết rằng thư mục đã tồn tại không? Tôi biết tôi có thể làm fs.stat()trước khi tạo thư mục, nhưng đó sẽ là hai lần truy cập vào hệ thống tập tin.

Thứ hai, có một tài liệu đầy đủ hoặc ít nhất là một tài liệu chi tiết hơn về Node.js có chứa các chi tiết về các đối tượng lỗi chứa gì, tham số nào biểu thị, v.v.


31
Nitlog nhỏ, nhưng thoát khỏi e &&. Nếu !ethất bại, thì bạn biết elà sự thật.
Tôi ghét Lười

Câu trả lời:


236

Cách tốt để làm điều này là sử dụng mô-đun mkdirp .

$ npm install mkdirp

Sử dụng nó để chạy chức năng yêu cầu thư mục. Gọi lại được gọi sau khi đường dẫn được tạo hoặc nếu đường dẫn đã tồn tại. Lỗi errđược đặt nếu mkdirp không thể tạo đường dẫn thư mục.

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

    // path exists unless there was an error

});

3
Đối với tôi, câu trả lời đúng (đọc 'không phụ thuộc') sẽ là câu trả lời thấp, bởi @Raugaral, sử dụng fs.exists(Sync).
Ricardo Pedroni

@meawoppl, đó là 'makenirectory'p. 'P' là không rõ.
andrew

4
@RicardoPedroni Cách chính xác là sử dụng một mô-đun. Các mô-đun thường hết lòng cố gắng giải quyết một vấn đề và thường được duy trì. Bạn có thể cập nhật chúng dễ dàng với npm. Ngoài ra, bạn đặc biệt nên tránh sử dụng fs.exists [Sync] vì việc sử dụng nó bao hàm các điều kiện chủng tộc.
1j01

16
@ 1j01 Tôi không tin cách chính xác là sử dụng mô-đun nếu nền tảng thực sự hỗ trợ hoạt động. Đó là một con đường dẫn đến sự hỗn loạn. Tôi phải đồng ý rằng có những câu trả lời tốt hơn từ quan điểm kỹ thuật.
c ..

2
@ 1j01 Ngoài ra, sử dụng các hoạt động Đồng bộ hóa ngụ ý các điều kiện cuộc đua bởi vì việc sử dụng chúng là một giải pháp cho họ.
c ..

192

Chỉnh sửa: Bởi vì câu trả lời này rất phổ biến, tôi đã cập nhật nó để phản ánh các thực tiễn cập nhật.

Nút> = 10

{ recursive: true }Tùy chọn mới của Node fshiện cho phép điều này nguyên bản. Tùy chọn này bắt chước hành vi của UNIX mkdir -p. Nó sẽ đệ quy đảm bảo mọi phần của đường dẫn tồn tại và sẽ không gây ra lỗi nếu bất kỳ phần nào trong số chúng xảy ra.

(Lưu ý: nó vẫn có thể gây ra các lỗi như EPERMhoặc EACCESS, vì vậy tốt hơn là vẫn xử lý nó try {} catch (e) {}nếu việc triển khai của bạn dễ bị ảnh hưởng.)

Phiên bản đồng bộ.

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

Phiên bản không đồng bộ

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

Phiên bản cũ hơn

Sử dụng một try {} catch (err) {} , bạn có thể đạt được điều này rất duyên dáng mà không gặp phải một điều kiện cuộc đua.

Để ngăn chặn thời gian chết giữa việc kiểm tra sự tồn tại và tạo thư mục, chúng tôi chỉ cần cố gắng tạo thẳng và bỏ qua lỗi nếu có EEXIST (thư mục đã tồn tại).

EEXISTTuy nhiên, nếu lỗi không phải là lỗi , chúng ta phải đưa ra lỗi, bởi vì chúng ta có thể xử lý một cái gì đó như EPERMhoặcEACCES

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

Đối với mkdir -p-like hành vi đệ quy, ví dụ ./a/b/c, bạn phải gọi nó trên tất cả các phần của dirpath, ví dụ như ./a, ./a/b,.a/b/c


var fs = Npm.require ('fs'); var dir = process.env.PWD + '/ files / users /' + this.userId + '/'; thử {fs.mkdirSync (dir); } Catch (e) {if (e.code! = 'EEXIST') throw e; }
Aaron

Tôi đã thử mã của bạn, tạo tập lệnh js sử dụng việc tạo danh mục như thế này: mkdirpSync (path.join (__ dirname, 'First', 'second', 'third', 'ololol', 'works')); Nhưng đã gặp lỗi này: $ node 1.js fs.js: 747 return bind.mkdir (pathModule._makeLong (path), ^ Error: EPERM, hoạt động không được phép 'C: \' tại Error (bản địa) tại Object.fs. mkdirSync (fs.js: 747: 18) tại mkdirpSync (C: \ Users \ MAXIM \ Desktop \ test \ 1.js: 15: 8) tại Object. <nặc danh> (C: \ Users \ MAXIM \ Desktop \ test \ 1.js: 19: 1) ... Bạn có thể đề xuất những gì có thể sai không? Được sử dụng trên windows rõ ràng :)
Alendorff

EPERM có vẻ như là một vấn đề về sự cho phép, vì vậy, kịch bản sẽ không thực hiện được việc thực thi bị phá vỡ
Barshe Marois

Tôi nghĩ rằng nó sẽ tốt hơn: var mkdirpSync = function (dirpath) {var part = dirpath.split (path.sep); for (var i = 1; i <= part.length; i ++) {thử {fs.mkdirSync (path.join.apply (null, part.slice (0, i))); } Catch (error) {if (error.code! = 'EEXIST') {lỗi ném; }}}}
manish

1
cảnh báo: nó không hoạt động nếu đường dẫn của bạn bắt đầu bằng /
acemtp

62

Nếu bạn muốn một lớp lót nhanh và bẩn, hãy sử dụng:

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

1
fs.existskhông được dùng nữa: nodejs.org/api/fs.html#fs_fs_exists_path_callback
adius

7
Tuy nhiên, fs.existsSync (...) không được dùng nữa, vì vậy câu trả lời này có vẻ ổn.
Dan Haywood

Đứng lên! Không hoạt động cho "dir / foo / bar" tức là thiếu tính năng cờ mkdir -p
Karl Pokus

Điều này cũng có một điều kiện cuộc đua
Evert

26

Các tài liệu node.js fs.mkdirvề cơ bản trì hoãn đến trang người dùng Linux cho mkdir(2). Điều đó chỉ ra rằng EEXISTcũng sẽ được chỉ định nếu đường dẫn tồn tại nhưng không phải là thư mục tạo ra trường hợp góc khó xử nếu bạn đi tuyến đường này.

Bạn có thể gọi điện tốt hơn fs.statsẽ cho bạn biết liệu đường dẫn có tồn tại hay không và nếu đó là một thư mục trong một cuộc gọi. Đối với (những gì tôi giả sử là) trường hợp bình thường trong đó thư mục đã tồn tại, đó chỉ là một hệ thống tập tin duy nhất.

Các fsphương thức mô-đun này là các trình bao bọc mỏng xung quanh API C gốc, do đó bạn phải kiểm tra các trang man được tham chiếu trong tài liệu của node.js để biết chi tiết.


19
Gọi stattrước mkdircó tiềm năng cho một điều kiện cuộc đua - hãy ghi nhớ điều này.
Roger Lipscombe

24

Bạn có thể sử dụng điều này:

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. Tôi không tin điều này hoạt động, statSyncsẽ gây ra lỗi nếu thực thể hoàn toàn không tồn tại, làm hỏng mã. Bạn cần phải bọc cái này trong một try/catchkhối.
Chris Foster

2
Xin lỗi tôi sai rồi. thay đổi "statSync" thành "tồn tại Đồng bộ hóa"
Raugaral

5
Theo nodejs.org/api/fs.html#fs_fs_mkdirsync_path_mode biến thể Đồng bộ hóa của mkdir không chấp nhận cuộc gọi lại
danwellman

1
Theo nodejs.org/api/fs.html#fs_fs_existssync_path , fs.existsSync()fs.exists()sẽ được phản đối.
pau.moreno

7

Tôi đề xuất một giải pháp không có mô-đun (tích lũy mô-đun không bao giờ được khuyến nghị cho khả năng bảo trì, đặc biệt đối với các chức năng nhỏ có thể được viết trong một vài dòng ...):

CẬP NHẬT CUỐI CÙNG :

Trong v10.12.0, các tùy chọn đệ quy của NodeJS:

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

CẬP NHẬT:

// 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()không được dùng trong nút v9. sử dụng fs.access()thay thế. (trả về undefinednếu tệp tồn tại; nếu không sẽ xảy ra lỗi ENOENT)
chharvey 28/03/18

Không có gói npm nào, nó hoạt động. Đó là một mã có giá trị. Cảm ơn
Karthik Sridharan

Điều này là khá tốt hơn để tạo một thư mục theo con đường dài hiện có;) Cảm ơn, người đàn ông.
Tsung Goh

1
Thế còn fs.mkdirSync('my/new/folder/create', {recursive: true})?
saitho

Cảm ơn ! Tôi cập nhật bài viết của mình để giúp đỡ người khác. Nút 10.12.0 là quá gần đây.
do


4

Đây là mã ES6 mà tôi sử dụng để tạo thư mục (khi nó không tồn tại):

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

Ghi chú:

  • Khi bắt đầu createDirectorychức năng, tôi bình thường hóa đường dẫn để đảm bảo rằng loại bộ tách đường dẫn của hệ điều hành sẽ được sử dụng một cách nhất quán (ví dụ: điều này sẽ biến C:\directory/testthành C:\directory\test(khi ở trên Windows)
  • fs.existsđang bị phản đối , đó là lý do tại sao tôi sử dụng fs.statđể kiểm tra xem thư mục đã tồn tại
  • Nếu một thư mục không tồn tại, mã lỗi sẽ là ENOENT( E rror NO ENT ry)
  • Thư mục sẽ được tạo bằng fs.mkdir
  • Tôi thích chức năng không đồng bộ fs.mkdirhơn chức năng chặn đối tác của nó fs.mkdirSyncvà vì gói Promisenày sẽ được đảm bảo rằng đường dẫn của thư mục sẽ chỉ được trả về sau khi thư mục được tạo thành công

Cảm ơn bạn vì một giải pháp sạch không liên quan đến các mô-đun không cần thiết. Nó làm việc hoàn hảo cho tôi. Tôi ước có nhiều câu trả lời như thế này!
Ken Lyon

3

Theo ý kiến ​​của tôi, tốt hơn hết là bạn không nên đếm các lần truy cập hệ thống tập tin trong khi bạn viết mã bằng Javascript. Tuy nhiên, (1) stat& mkdirvà (2) mkdirvà kiểm tra (hoặc loại bỏ) mã lỗi, cả hai cách đều là cách đúng để làm những gì bạn muốn.


-1, tôi không thấy cách kiểm tra hoặc loại bỏ cả hai có thể là cách đúng để làm điều đó. Đây là khá nhiều một câu trả lời không.
Matt Ball

Đó là một cách tốt để mkdir một thư mục hoặc sử dụng thư mục hiện có. Tôi không thấy lý do tại sao bạn không nhìn thấy. Kiểm tra mã lỗi là lịch sự tốt, trong khi loại bỏ mã lỗi chỉ là một lỗi tốt. bạn không đồng ý à
Chul-Woong Yang

1
Có thể đây là một vấn đề rào cản ngôn ngữ, nhưng tôi đọc nó như thể không trả lời câu hỏi mà OP đang hỏi.
Matt Ball

Tôi thấy quan điểm của bạn là gì. Tuy nhiên, tôi tin rằng có nhiều cách để làm mọi thứ đúng. Cảm ơn.
Chul-Woong Yang

2

tạo thư mục tên động cho mỗi người dùng ... sử dụng mã này

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

Bạn có thể thực hiện tất cả điều này với mô-đun Hệ thống tệp.

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.
})

Bạn thực sự thậm chí không cần kiểm tra nếu thư mục tồn tại. Đoạn mã sau cũng đảm bảo rằng thư mục đã tồn tại hoặc được tạo.

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

Câu trả lời của Raugaral nhưng với chức năng -p. Xấu xí, nhưng nó hoạt động:

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

Giống như một giải pháp thay thế mới hơn cho câu trả lời của Teemu Ikonen , rất đơn giản và dễ đọc, là sử dụng ensureDirphương pháp của fs-extragói.

Nó không chỉ có thể được sử dụng như một sự thay thế trắng trợn cho fsmô-đun tích hợp, mà còn có rất nhiều chức năng khác ngoài các chức năng củafs gói.

Các ensureDirphương pháp, như tên cho thấy, đảm bảo rằng các thư mục tồn tại. Nếu cấu trúc thư mục không tồn tại, nó được tạo. Giốngmkdir -p . Không chỉ thư mục kết thúc, thay vào đó toàn bộ đường dẫn được tạo nếu chưa tồn tại.

asyncphiên bản được cung cấp ở trên là phiên bản của nó. Nó cũng có một phương thức đồng bộ để thực hiện điều này dưới dạng ensureDirSyncphương thức.


0

Câu trả lời của @ Liber Nghiệp ở trên không hiệu quả với tôi (Node v8.10.0). Một chút sửa đổi đã làm nên mánh khóe nhưng tôi không chắc đây có phải là một cách đúng đắn hay không. Xin đề nghị.

// 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');
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.