Harry
Harry

Reputation: 54939

node.js recursive write file directory

How do I use nodejs to write a file, if the file is in a directory that may or may not exist?

It's kind of similar to this question:

node.js Write file with directories?

Only I need a solution that creates the file while node-fs only makes directories.

Upvotes: 7

Views: 12075

Answers (7)

Mouneer
Mouneer

Reputation: 13489

// Create parentDir recursively if it doesn't exist!
const parentDir = 'path/to/parent';
parentDir.split('/').forEach((dir, index, splits) => {
  const curParent = splits.slice(0, index).join('/');
  const dirPath = path.resolve(curParent, dir);
  if (!fs.existsSync(dirPath)) {
    fs.mkdirSync(dirPath);
  }
});

// Create file.js inside the parentDir
fs.writeFileSync(`${parentDir}/file.js`, 'file Content', 'utf8');

Upvotes: 0

A T
A T

Reputation: 13826

For TypeScript users here's one I just wrote, based on mkdirP:

const _0777 = parseInt('0777', 8);

export function mkdirP(dir: string, opts: {
    fs?: {
        mkdir: (path: string | Buffer, mode: number,
                callback?: (err?: NodeJS.ErrnoException) => void) => void,
        stat: (path: string | Buffer,
               callback?: (err: NodeJS.ErrnoException,
                           stats: fs.Stats) => any) => void
    }, mode?: number}, f: Function, made?) {
    dir = resolve(dir);
    if (typeof opts === 'function') {
        f = <Function>opts;
        opts = {};
    }
    else if (!opts || typeof opts !== 'object')
        opts = {mode: <number>opts};

    opts.mode = opts.mode || (_0777 & (~process.umask()));
    opts.fs = opts.fs || fs;

    if (!made) made = null;

    const cb = f || (() => undefined);

    opts.fs.mkdir(dir, opts.mode, function (error) {
        if (!error) {
            made = made || dir;
            return cb(null, made);
        }
        switch (error.code) {
            case 'ENOENT':
                mkdirP(dirname(dir), opts, function (err, made) {
                    if (err) cb(err, made);
                    else mkdirP(dir, opts, cb, made);
                });
                break;

            default:
                opts.fs.stat(dir, function (e, stat) {
                    if (e || !stat.isDirectory()) cb(error || e, made);
                    else cb(null, made);
                });
        }
    });
}

JavaScript version just remove the type annotations from the signature, i.e.: turn those first few lines to: (dir, opts, mode, f, made) {.

Upvotes: 0

Perspectivus
Perspectivus

Reputation: 990

Since fs.exists() is deprecated, here's another async version using fs.access() and no external npm modules:

"use strict";
var fs =  require('fs');
var path = require('path');

var fileName = '\\tmp\\a\\b\\c\\d.txt'; // e.g. using Windows path separator
var contents = 'any content';

createDirectoryAndFile(fileName, contents);

function createDirectoryAndFile(fileName, contents) {
  var dirName = path.dirname(fileName);
  var pathAsArray = dirName.split(path.sep);
  _createDirectoryAndFile(pathAsArray, '', function() {
    fs.open(fileName, 'w+', function(error, data) {
      fs.writeFile(fileName, contents, function(error) {});
    });
  });
}

function _createDirectoryAndFile(pathAsArray, pathSoFar, createFile) {
  if (!pathAsArray || pathAsArray.length === 0) {
    createFile();
    return;
  }

  var dir = pathAsArray.shift();
  pathSoFar = pathSoFar + dir  + path.sep;
  fs.access(pathSoFar, function(error) {
    if (error) { // directory does not exist
      fs.mkdir(pathSoFar, function(error) {
        if (!error) {
          _createDirectoryAndFile(pathAsArray, pathSoFar, createFile);
        }
      });
    } else {
      _createDirectoryAndFile(pathAsArray, pathSoFar, createFile);
    }
  });
}

This of course needs to be improved by adding error handling and supporting permissions.

Upvotes: 0

user4312034
user4312034

Reputation: 1

you can use https://github.com/douzi8/file-system

var file = require('file-system');
file.mkdir('1/2/3/4/5', [mode], function(err) {});

Upvotes: -2

Myrne Stol
Myrne Stol

Reputation: 11438

I just wrote this as answer to How to write file if parent folder doesn't exist? . Might be useful for someone stumbling upon this in Google:

Use mkdirp in combination with path.dirname first.

var mkdirp = require("mkdirp")
var fs = require("fs")
var getDirName = require("path").dirname
function writeFile (path, contents, cb) {
  mkdirp(getDirName(path), function (err) {
    if (err) return cb(err)
    fs.writeFile(path, contents, cb)
  })
}

Upvotes: 3

Gabriel Llamas
Gabriel Llamas

Reputation: 18427

From FileUtils:

Modify the functions to satisfy yours needs! But seriously, use a module instead of writing your own!

createDirectory(): Creates a directory. If any of the previous directories that form the path don't exist, they are created. Default permissions: 0777.

File.prototype.createDirectory = function (cb){
    if (cb) cb = cb.bind (this);
    if (!this._path){
        if (cb) cb (NULL_PATH_ERROR, false);
        return;
    }
    if (!canWriteSM (this._usablePath)){
        if (cb) cb (SECURITY_WRITE_ERROR, false);
        return;
    }

    var mkdirDeep = function (path, cb){
        path.exists (function (exists){
            if (exists) return cb (null, false);

            FS.mkdir (path.getPath (), function (error){
                if (!error) return cb (null, true);

                var parent = path.getParentFile ();
                if (parent === null) return cb (null, false);

                mkdirDeep (parent, function (error, created){
                    if (created){
                        FS.mkdir (path.getPath (), function (error){
                            cb (error, !error);
                        });
                    }else{
                        parent.exists (function (exists){
                            if (!exists) return cb (null, false);

                            FS.mkdir (path.getPath (), function (error){
                                cb (error, !error);
                            });
                        });
                    }
                });
            });
        });
    };

    mkdirDeep (this.getAbsoluteFile (), function (error, created){
        if (cb) cb (error, created);
    });
};

createNewFile(): Creates a new file. Default permissions: 0666.

File.prototype.createNewFile = function (cb){
    if (cb) cb = cb.bind (this);
    if (!this._path){
        if (cb) cb (NULL_PATH_ERROR, false);
        return;
    }

    if (!canWriteSM (this._usablePath)){
        if (cb) cb (SECURITY_WRITE_ERROR, false);
        return;
    }

    var path = this._usablePath;
    PATH.exists (path, function (exists){
        if (exists){
            if (cb) cb (null, false);
        }else{
            var s = FS.createWriteStream (path);
            s.on ("error", function (error){
                if (cb) cb (error, false);
            });
            s.on ("close", function (){
                if (cb) cb (null, true);
            });
            s.end ();
        }
    });
};

Upvotes: 6

xvatar
xvatar

Reputation: 3259

You can just use something like createWriteStream.

It will just create the file if it didn't exist.

Upvotes: 0

Related Questions