-
-
Save drodsou/de2ba6291aea67ffc5bc4b52d8c32abd to your computer and use it in GitHub Desktop.
// -- updated in 2020/04/19 covering the issues in the comments to this point | |
// -- remember you also have things like `ensureDirSync` from https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir-sync.md | |
const fs = require('fs') | |
function writeFileSyncRecursive(filename, content, charset) { | |
// -- normalize path separator to '/' instead of path.sep, | |
// -- as / works in node for Windows as well, and mixed \\ and / can appear in the path | |
let filepath = filename.replace(/\\/g,'/'); | |
// -- preparation to allow absolute paths as well | |
let root = ''; | |
if (filepath[0] === '/') { | |
root = '/'; | |
filepath = filepath.slice(1); | |
} | |
else if (filepath[1] === ':') { | |
root = filepath.slice(0,3); // c:\ | |
filepath = filepath.slice(3); | |
} | |
// -- create folders all the way down | |
const folders = filepath.split('/').slice(0, -1); // remove last item, file | |
folders.reduce( | |
(acc, folder) => { | |
const folderPath = acc + folder + '/'; | |
if (!fs.existsSync(folderPath)) { | |
fs.mkdirSync(folderPath); | |
} | |
return folderPath | |
}, | |
root // first 'acc', important | |
); | |
// -- write file | |
fs.writeFileSync(root + filepath, content, charset); | |
} | |
// -- Tests done that work properly: | |
// -- both in WSL and CMD | |
// writeFileSyncRecursive('data.json', '{}', 'utf8'); | |
// writeFileSyncRecursive('public/new-user/data.json', '{}', 'utf8'); | |
// writeFileSyncRecursive('public\\new-user\\data.json', '{}', 'utf8'); | |
// writeFileSyncRecursive('./public/new-user/data.json', '{}', 'utf8'); | |
// writeFileSyncRecursive('.\\public\\new-user\\data.json', '{}', 'utf8'); | |
// writeFileSyncRecursive('/tmp/public\\new-user\\data.json', '{}', 'utf8'); | |
// -- only in WSL (in CMD creates a 'C:\c' folder) | |
// writeFileSyncRecursive('/c/tmp/writefilesync/public/new-user/data.json', '{}', 'utf8'); | |
// -- only in CMD (in WSL throws error no such file or directory c:/tmp) | |
// writeFileSyncRecursive('c:\\tmp\\writefilesync\\public\\new-user\\data.json', '{}', 'utf8'); | |
// writeFileSyncRecursive('c:/tmp/writefilesync/public/new-user/data.json', '{}', 'utf8'); | |
/* | |
// former implementation that received comments until 2020/04/19 | |
// fixed missing second parameter in reduce (irkreja comment) | |
// works well only with relative paths | |
// asumes paths passed with / separator even in windows | |
function writeFileSyncRecursive (filename, content, charset) { | |
// create folder path if not exists | |
filename.split('/').slice(0,-1).reduce( (last, folder)=>{ | |
let folderPath = last ? (last + '/' + folder) : folder | |
if (!fs.existsSync(folderPath)) fs.mkdirSync(folderPath) | |
return folderPath | |
},''); // fixed missing second parameter of reduce | |
fs.writeFileSync(filename, content, charset) | |
} | |
*/ |
Thanks. This worked great :)
writeFileSyncRecursive(`public/new-users/data.json`, content);
this thrown error if public directory does not exist.
Error: ENOENT: no such file or directory, mkdir 'public/new-users'
Thanks all for the unexpected comments.
Due to this attention I've updated the code to work more reliably in more cases.
const fs = require('fs');
const path = require('path');
const _ = require('lodash');
const { promisify } = require('util');
const writeFile = promisify(fs.writeFile);
const mkdir = promisify(fs.mkdir);
const exists = promisify(fs.exists);
async function writeFileRecursive(filename, content, charset = 'UTF-8') {
const filePathParts = _.split(filename, path.sep);
if (_.size(filePathParts) > 1) {
const folderPath = _.join(_.slice(filePathParts, 0, _.size(filePathParts) - 1), path.sep);
const folderExists = await exists(folderPath);
if (!folderExists) {
await mkdir(folderPath, { recursive: true });
}
}
return writeFile(filename, content, charset);
}
This is exactly what I was after. Good stuff.
I'd consider just calling fs.mkdirSync(argv.outputDirectory, {recursive: true});
first instead (or the async version)
something simpler could be
function writeFileSyncRecursive(filename, content = '') {
fs.mkdirSync(path.dirname(filename), {recursive: true})
fs.writeFileSync(filename, content)
}
something simpler could be
function writeFileSyncRecursive(filename, content = '') { fs.mkdirSync(path.dirname(filename), {recursive: true}) fs.writeFileSync(filename, content) }
this will create the file name as folder, for example if the filename variable is "c:/users/someone/folder/config.js", config.js will be created as folder, but I agree we can start something from mkdir
something simpler could be
function writeFileSyncRecursive(filename, content = '') { fs.mkdirSync(path.dirname(filename), {recursive: true}) fs.writeFileSync(filename, content) }
this will create the file name as folder, for example if the filename variable is "c:/users/someone/folder/config.js", config.js will be created as folder, but I agree we can start something from mkdir
path.dirname
strips the file name off of the path before creating the folders. The function works as intended.
ex.
// This returns "c:/users/someone/folder"
path.dirname("c:/users/someone/folder/config.js")
something simpler could be
function writeFileSyncRecursive(filename, content = '') { fs.mkdirSync(path.dirname(filename), {recursive: true}) fs.writeFileSync(filename, content) }this will create the file name as folder, for example if the filename variable is "c:/users/someone/folder/config.js", config.js will be created as folder, but I agree we can start something from mkdir
path.dirname
strips the file name off of the path before creating the folders. The function works as intended.ex.
// This returns "c:/users/someone/folder" path.dirname("c:/users/someone/folder/config.js")
This is the the only one that works cross platform, and the bonus is it's the smallest in terms of lines of code too 👍💯
Thanks for this! To make this platform agnostic, you could use
path.sep
, instead of hardcoding the separator: