Skip to content

Instantly share code, notes, and snippets.

@drodsou
Last active June 5, 2024 15:57
Show Gist options
  • Save drodsou/de2ba6291aea67ffc5bc4b52d8c32abd to your computer and use it in GitHub Desktop.
Save drodsou/de2ba6291aea67ffc5bc4b52d8c32abd to your computer and use it in GitHub Desktop.
Like writeFileSync but creating all folder paths if not exist
// -- 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)
}
*/
@Hasankanso
Copy link

Hasankanso commented Sep 13, 2022

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

@aquacash5
Copy link

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")

@DalSoft
Copy link

DalSoft commented Jun 5, 2024

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 👍💯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment