如何使用节点的fs.mkdirSync创建完整路径?

问题描述 投票:116回答:20

如果它不存在,我正在尝试创建一个完整的路径。

代码如下所示:

var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest); 

只要只有一个子目录(像'dir1'这样的newDest),这个代码就可以运行,但是当有一个像''dir1 / dir2'这样的目录路径时,它失败了,错误:ENOENT,没有这样的文件或目录

我希望能够根据需要使用尽可能少的代码行创建完整路径。

我读到fs上有一个递归选项,并尝试这样做

var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest,'0777', true);

我觉得递归创建一个不存在的目录应该很简单。我是否遗漏了某些内容或是否需要解析路径并检查每个目录并创建它(如果它尚不存在)?

我是Node的新手。也许我正在使用旧版本的FS?

node.js fs
20个回答
46
投票

一种选择是使用shelljs module

npm install shelljs

var shell = require('shelljs');
shell.mkdir('-p', fullPath);

从该页面:

可用选项:

p:完整路径(如有必要,将创建中间目录)

正如其他人所指出的那样,还有其他更集中的模块。但是,在mkdirp之外,它还有大量其他有用的shell操作(比如grep等......),它适用于windows和* nix


2
投票

您可以使用下一个功能

const recursiveUpload =(path:string)=> {const paths = path.split(“/”)

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

它的作用是什么:

  1. 创建fs.mkdirSync变量,它将每个路径自身存储为数组的元素。
  2. 在数组中每个元素的末尾添加“/”。
  3. 为周期做准备: 从数组元素的串联创建一个目录,索引从0到当前迭代。基本上,它是递归的。

希望有所帮助!

顺便说一句,在Node v10.12.0中,您可以通过将其作为附加参数来创建递归路径。

const path = require('path'); const fs = require('fs'); let dir = "C:\\temp\\dir1\\dir2\\dir3"; function createDirRecursively(dir) { if (!fs.existsSync(dir)) { createDirRecursively(path.join(dir, "..")); fs.mkdirSync(dir); } } createDirRecursively(dir); //creates dir1\dir2\dir3 in C:\temp

const fullPath = paths.reduce((accumulator, current) => { fs.mkdirSync(accumulator) return `${accumulator}/${current}` }) fs.mkdirSync(fullPath) return fullPath }


1
投票

太多的答案,但这里是一个没有递归的解决方案,通过拆分路径,然后从左到右建立它再次备份

paths

对于那些担心Windows与Linux兼容性的人来说,只需在上面的两个事件中用双反斜杠'\'替换正斜杠,但TBH我们说的是节点fs而不是windows命令行,而前者非常宽容,上面的代码将简单地工作Windows是一个更完整的跨平台解决方案。


1
投票
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
  if (err) throw err;
});

1
投票

您可以简单地以递归方式检查文件夹是否存在于路径中,并在检查文件夹是否不存在时创建该文件夹。 (没有外部图书馆)

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

0
投票

以递归方式创建目录的异步方法:

function mkdirRecursiveSync(path) {
    let paths = path.split(path.delimiter);
    let fullPath = '';
    paths.forEach((path) => {

        if (fullPath === '') {
            fullPath = path;
        } else {
            fullPath = fullPath + '/' + path;
        }

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

0
投票

这是我对nodejs的const fs = require('fs'); try { fs.mkdirSync(path, { recursive: true }); } catch (error) { // this make script keep running, even when folder already exist console.log(error); } 的命令式版本。

function checkAndCreateDestinationPath (fileDestination) {
    const dirPath = fileDestination.split('/');
    dirPath.forEach((element, index) => {
        if(!fs.existsSync(dirPath.slice(0, index + 1).join('/'))){
            fs.mkdirSync(dirPath.slice(0, index + 1).join('/')); 
        }
    });
}

0
投票

这种方法怎么样:

import fs from 'fs'

const mkdirRecursive = function(path, callback) {
  let controlledPaths = []
  let paths = path.split(
    '/' // Put each path in an array
  ).filter(
    p => p != '.' // Skip root path indicator (.)
  ).reduce((memo, item) => {
    // Previous item prepended to each item so we preserve realpaths
    const prevItem = memo.length > 0 ? memo.join('/').replace(/\.\//g, '')+'/' : ''
    controlledPaths.push('./'+prevItem+item)
    return [...memo, './'+prevItem+item]
  }, []).map(dir => {
    fs.mkdir(dir, err => {
      if (err && err.code != 'EEXIST') throw err
      // Delete created directory (or skipped) from controlledPath
      controlledPaths.splice(controlledPaths.indexOf(dir), 1)
      if (controlledPaths.length === 0) {
        return callback()
      }
    })
  })
}

// Usage
mkdirRecursive('./photos/recent', () => {
  console.log('Directories created succesfully!')
})

这适用于相对路径。


0
投票

基于mkdirp零依赖性答案,这里是一个稍微初学者友好的function mkdirSyncP(location) { let normalizedPath = path.normalize(location); let parsedPathObj = path.parse(normalizedPath); let curDir = parsedPathObj.root; let folders = parsedPathObj.dir.split(path.sep); folders.push(parsedPathObj.base); for(let part of folders) { curDir = path.join(curDir, part); if (!fs.existsSync(curDir)) { fs.mkdirSync(curDir); } } } 变体,作为一个模块:

if (!fs.existsSync(pathToFile)) {
            var dirName = "";
            var filePathSplit = pathToFile.split('/');
            for (var index = 0; index < filePathSplit.length; index++) {
                dirName += filePathSplit[index]+'/';
                if (!fs.existsSync(dirName))
                    fs.mkdirSync(dirName);
            }
        }

0
投票

像这样干净:)

mouneer's

-1
投票

Exec在windows上可能很乱。有一个更“nodie”的解决方案。从根本上说,您有一个递归调用来查看目录是否存在并潜入子级(如果存在)或创建它。这是一个函数,它将创建子节点并在完成时调用函数:

Typescript

}


237
投票

编辑

NodeJS版本10.12.0mkdirmkdirSync添加了原生支持,以recursive: true选项递归创建目录,如下所示:

fs.mkdirSync(targetDir, { recursive: true });

如果你更喜欢fs Promises API,你可以写

fs.promises.mkdir(targetDir, { recursive: true });

原始答案

如果目录不存在,则递归创建目录! (零依赖)

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

function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) {
  const sep = path.sep;
  const initDir = path.isAbsolute(targetDir) ? sep : '';
  const baseDir = isRelativeToScript ? __dirname : '.';

  return targetDir.split(sep).reduce((parentDir, childDir) => {
    const curDir = path.resolve(baseDir, parentDir, childDir);
    try {
      fs.mkdirSync(curDir);
    } catch (err) {
      if (err.code === 'EEXIST') { // curDir already exists!
        return curDir;
      }

      // To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
      if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure.
        throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
      }

      const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1;
      if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) {
        throw err; // Throw if it's just the last created dir.
      }
    }

    return curDir;
  }, initDir);
}

Usage

// Default, make directories relative to current working directory.
mkDirByPathSync('path/to/dir');

// Make directories relative to the current script.
mkDirByPathSync('path/to/dir', {isRelativeToScript: true});

// Make directories with an absolute path.
mkDirByPathSync('/path/to/dir');

Demo

Try It!

Explanations

  • [更新]此解决方案处理特定于平台的错误,例如适用于Mac的EISDIR和适用于Windows的EPERMEACCES。感谢@PediT。,@ JohnQ,@ deed02392,@ robyoder和@Almenon的所有报道评论。
  • 该解决方案处理相对路径和绝对路径。感谢@john评论。
  • 在相对路径的情况下,将在当前工作目录中创建(解析)目标目录。要相对于当前脚本目录解析它们,请传递{isRelativeToScript: true}
  • 使用path.seppath.resolve(),而不仅仅是/连接,以避免跨平台问题。
  • 使用fs.mkdirSync并使用try/catch处理错误,如果抛出来处理竞争条件:另一个进程可能会在调用fs.existsSync()fs.mkdirSync()之间添加文件并导致异常。 实现这一目标的另一种方法是检查文件是否存在然后创建它,即if (!fs.existsSync(curDir) fs.mkdirSync(curDir);。但这是一种反模式,使代码容易受到竞争条件的影响。感谢@GershomMaes关于目录存在检查的评论。
  • 需要Node v6及更高版本才能支持解构。 (如果使用旧的Node版本实现此解决方案时遇到问题,请给我留言)

-1
投票

这个版本在Windows上的效果比最佳答案更好,因为它理解import * as fs from 'fs'; import * as path from 'path'; /** * Recursively creates directories until `targetDir` is valid. * @param targetDir target directory path to be created recursively. * @param isRelative is the provided `targetDir` a relative path? */ export function mkdirRecursiveSync(targetDir: string, isRelative = false) { const sep = path.sep; const initDir = path.isAbsolute(targetDir) ? sep : ''; const baseDir = isRelative ? __dirname : '.'; targetDir.split(sep).reduce((prevDirPath, dirToCreate) => { const curDirPathToCreate = path.resolve(baseDir, prevDirPath, dirToCreate); try { fs.mkdirSync(curDirPathToCreate); } catch (err) { if (err.code !== 'EEXIST') { throw err; } // caught EEXIST error if curDirPathToCreate already existed (not a problem for us). } return curDirPathToCreate; // becomes prevDirPath on next call to reduce }, initDir); } function makedir(fullpath) { let destination_split = fullpath.replace('/', '\\').split('\\') let path_builder = destination_split[0] $.each(destination_split, function (i, path_segment) { if (i < 1) return true path_builder += '\\' + path_segment if (!fs.existsSync(path_builder)) { fs.mkdirSync(path_builder) } }) } ,因此正斜杠可以在Windows上运行。支持绝对路径和相对路径(相对于fs = require('fs'); makedirs = function(path, func) { var pth = path.replace(/['\\]+/g, '/'); var els = pth.split('/'); var all = ""; (function insertOne() { var el = els.splice(0, 1)[0]; if (!fs.existsSync(all + el)) { fs.mkdirSync(all + el); } all += el + "/"; if (els.length == 0) { func(); } else { insertOne(); } })(); )。

/

74
投票

一个更健全的答案是使用mkdirp

var mkdirp = require('mkdirp');

mkdirp('/path/to/dir', function (err) {
    if (err) console.error(err)
    else console.log('dir created')
});

然后继续将文件写入完整路径:

fs.writeFile ('/path/to/dir/file.dat'....

46
投票

fs-extra添加了本机fs模块中未包含的文件系统方法。这是对fs的替代。

安装fs-extra

$ npm install --save fs-extra

const fs = require("fs-extra");
// Make sure the output directory is there.
fs.ensureDirSync(newDest);

有同步和异步选项。

https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir.md


29
投票

使用reduce我们可以验证每个路径是否存在并在必要时创建它,这样我认为它更容易理解。编辑,感谢@Arvin,我们应该使用path.sep来获取适当的特定于平台的路径段分隔符。

const path = require('path');

// Path separators could change depending on the platform
const pathToCreate = 'path/to/dir'; 
pathToCreate
 .split(path.sep)
 .reduce((prevPath, folder) => {
   const currentPath = path.join(prevPath, folder, path.sep);
   if (!fs.existsSync(currentPath)){
     fs.mkdirSync(currentPath);
   }
   return currentPath;
 }, '');

28
投票

此功能已添加到版本10.12.0中的node.js,因此它就像将选项{recursive: true}作为第二个参数传递给fs.mkdir()调用一样简单。见example in the official docs

无需外部模块或您自己的实现。


6
投票

我知道这是一个老问题,但nodejs v10.12.0现在支持这个本地,recursive选项设置为true。 fs.mkdir

// Creates /tmp/a/apple, regardless of whether `/tmp` and /tmp/a exist.
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
  if (err) throw err;
});

4
投票

现在使用Node JS> = qazxsw poi,你可以使用qazxsw poi qazxsw poi


2
投票

Windows示例(没有额外的依赖项和错误处理)

10.12.0
© www.soinside.com 2019 - 2024. All rights reserved.