如果不存在,如何创建目录?

Is this the right way to create a directory if it doesn't exist. It should have full permission for the script and readable by others.

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

转载于:https://stackoverflow.com/questions/21194934/node-how-to-create-a-directory-if-doesnt-exist

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

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

No, for multiple reasons.

  1. The path module does not have an exists/existsSync method. It is in the fs module. (Perhaps you just made a typo in your question?)

  2. The docs explicitly discourage you from using exists.

    fs.exists() is an anachronism and exists only for historical reasons. There should almost never be a reason to use it in your own code.

    In particular, checking if a file exists before opening it is an anti-pattern that leaves you vulnerable to race conditions: another process may remove the file between the calls to fs.exists() and fs.open(). Just open the file and handle the error when it's not there.

    Since we're talking about a directory rather than a file, this advice implies you should just unconditionally call mkdir and ignore EEXIST.

  3. In general, You should avoid the *Sync methods. They're blocking, which means absolutely nothing else in your program can happen while you go to the disk. This is a very expensive operation, and the time it takes breaks the core assumption of node's event loop.

    The *Sync methods are usually fine in single-purpose quick scripts (those that do one thing and then exit), but should almost never be used when you're writing a server: your server will be unable to respond to anyone for the entire duration of the I/O requests. If multiple client requests require I/O operations, your server will very quickly grind to a halt.


    The only time I'd consider using *Sync methods in a server application is in an operation that happens once (and only once), at startup. For example, require actually uses readFileSync to load modules.

    Even then, you still have to be careful because lots of synchronous I/O can unnecessarily slow down your server's startup time.


    Instead, you should use the asynchronous I/O methods.

So if we put together those pieces of advice, we get something like this:

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

And we can use it like this:

ensureExists(__dirname + '/upload', 0744, function(err) {
    if (err) // handle folder creation error
    else // we're all good
});

Of course, this doesn't account for edge cases like

  • What happens if the folder gets deleted while your program is running? (assuming you only check that it exists once during startup)
  • What happens if the folder already exists but with the wrong permissions?

I have found and npm module that works like a charm for this. It's simply do a recursively mkdir when needed, like a "mkdir -p ".

https://www.npmjs.com/package/mkdirp

The best solution would be to use the npm module called node-fs-extra. It has a method called mkdir which creates the directory you mentioned. If you give a long directory path, it will create the parent folders automatically. The module is a super set of npm module fs, so you can use all the functions in fs also if you add this module.

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

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

This may help you :)

I'd like to add a Typescript Promise refactor of josh3736's answer.

It does the same thing and has the same edge cases, it just happens to use Promises, typescript typedefs and works with "use 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
                }
            });
    });
}

Here is a little function to recursivlely create directories:

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
  }, '')
}
var dir = 'path/to/dir';
try {
  fs.mkdirSync(dir);
} catch(e) {
  if (e.code ~= 'EEXIST') throw e;
}

Using async / await:

const mkdirP = async (directory) => {
  try {
    return await fs.mkdirAsync(directory);
  } catch (error) {
    if (error.code != 'EEXIST') {
      throw e;
    }
  }
};

You will need to promisify fs:

import nodeFs from 'fs';
import bluebird from 'bluebird';

const fs = bluebird.promisifyAll(nodeFs);

Just in case any one interested in the one line version. :)

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

You can just use mkdir and catch the error if the folder exists.
This is async (so best practice) and safe.

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

(Optionally add a second argument with the mode.)


Other thoughts:

  1. You could use then or await by using native promisify.

    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. You can make your own promise method, something like (untested):

    let mkdirAsync = (path, mode) => new Promise(
       (resolve, reject) => mkdir (path, mode, 
          err => (err && err.code !== 'EEXIST') ? reject(err) : resolve()
          )
       )
    
  3. For synchronous checking, you can use:

    fs.existsSync(path) || fs.mkdirSync(path)
    
  4. Or you can use a library, the two most popular being

    • mkdirp (just does folders)
    • fsextra (supersets fs, adds lots of useful stuff)