posit labs suggestion of a duplicate question in the comments is probably wise if this is just something you want done. The top rated answer suggests the package ncp.
Assuming you're in this to learn, however...
The objective is a function that
- Takes a source directory and target directory
- Enumerates the contents
- Copies files from source to target
- Makes all source directories in target and recursively calls itself on each directory pair
Be aware: this solution is very much a demo and should not be used in production. The use of recursion could bite if the file system is very deep, but the fact that the code is all synchronous (*Sync) can really slow this down.
Instead of string building your paths, use the path module. It handles cross platform and strange inputs and edge cases.
First, two helper functions: ensuring directories exist where they should and copying a file from one path to another. Ultimately, these do the 2 real tasks in mirroring two directories.
var ensureDirectoryExists = function(path) {
if (fs.existsSync(path)) return;
fs.mkdirSync(path);
}
var copyFile = function(sourceFile, targetFile) {
if (fs.existsSync(targetFile)) return;
fs.writeFileSync(targetFile, fs.readFileSync(sourceFile));
}
Then the main work. Ensure the directories exist and read the contents.
ensureDirectoryExists(source);
ensureDirectoryExists(target);
var sourceList = fs.readdirSync(source);
var targetList = fs.readdirSync(target);
Then for every element in the source directory
sourceList.forEach(function(sourceFile) { /* code */ })
Quickly check if it already exists (just by name. For real work, you should check types and a checksum)
if (targetList.indexOf(sourceFile) > -1) return;
Gather information on this target (fs.Stats are detailed in the manual)
var fullSourcePath = path.join(source, sourceFile);
var fullTargetPath = path.join(target, sourceFile);
var fileStats = fs.statSync(fullSourcePath);
Last, perform the correct action based on the type. Files are copied, directories are ensured to exist and the recursively called, and anything else causes the program to shrug and keep going.
if (fileStats.isFile()) {
copyFile(fullSourcePath, fullTargetPath);
} else if (fileStats.isDirectory()) {
copyDirectories(fullSourcePath, fullTargetPath);
} else {
// there can be other things in the list. See https://nodejs.org/api/fs.html#fs_class_fs_stats
console.log(`Not sure what ${sourceFile} is. Ignoring.`);
}
Complete solution
var fs = require('fs');
var path = require('path');
var ensureDirectoryExists = function(path) {
if (fs.existsSync(path)) return;
fs.mkdirSync(path);
}
var copyFile = function(sourceFile, targetFile) {
// console.log(`copying from ${sourceFile} to ${targetFile}`);
if (fs.existsSync(targetFile)) return;
fs.writeFileSync(targetFile, fs.readFileSync(sourceFile));
// or with streams. Note this ignores errors. Read more here: https://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js
// fs.createReadStream(sourceFile).pipe(fs.createWriteStream(targetFile));
}
var copyDirectories = function(source, target) {
// console.log(`copying from ${source} to ${target}`);
// ensure the directories exist
ensureDirectoryExists(source);
ensureDirectoryExists(target);
var sourceList = fs.readdirSync(source);
var targetList = fs.readdirSync(target);
//sourceList has the contents of the directories
sourceList.forEach(function(sourceFile) {
// omit this file it it already exists
// Note that this is quite naive, but will work for demo purposes
if (targetList.indexOf(sourceFile) > -1) return;
var fullSourcePath = path.join(source, sourceFile);
var fullTargetPath = path.join(target, sourceFile);
var fileStats = fs.statSync(fullSourcePath);
// console.log(`${sourceFile} is a ${fileStats.isFile() ? 'file' : (fileStats.isDirectory() ? 'directory' : '??')}.`);
if (fileStats.isFile()) {
copyFile(fullSourcePath, fullTargetPath);
} else if (fileStats.isDirectory()) {
copyDirectories(fullSourcePath, fullTargetPath);
} else {
// there can be other things in the list. See https://nodejs.org/api/fs.html#fs_class_fs_stats
console.log(`Not sure what ${sourceFile} is. Ignoring.`);
}
});
}
copyDirectories(
path.join(__dirname, 'source'),
path.join(__dirname, 'target')
)