是否有更简单的方法来复制文件夹及其所有内容,而无需手动执行fs.readir
,fs.readfile
,fs.writefile
一系列递归?
只是想知道我是否错过了一个理想情况下会像这样工作的功能
fs.copy("/path/to/source/folder","/path/to/destination/folder");
答案 0 :(得分:93)
您可以使用ncp模块。我认为这就是你需要的东西
答案 1 :(得分:53)
这是我在没有任何额外模块的情况下解决此问题的方法。只需使用内置的fs
和path
模块。
注意:这确实使用了fs的读/写功能,因此它不会复制任何元数据(创建时间等)。从节点8.5开始,有一个copyFileSync
函数可用于调用OS复制函数,因此也复制元数据。我还没有测试它们,但它应该可以替换它们。 (见https://nodejs.org/api/fs.html#fs_fs_copyfilesync_src_dest_flags)
var fs = require('fs');
var path = require('path');
function copyFileSync( source, target ) {
var targetFile = target;
//if target is a directory a new file with the same name will be created
if ( fs.existsSync( target ) ) {
if ( fs.lstatSync( target ).isDirectory() ) {
targetFile = path.join( target, path.basename( source ) );
}
}
fs.writeFileSync(targetFile, fs.readFileSync(source));
}
function copyFolderRecursiveSync( source, target ) {
var files = [];
//check if folder needs to be created or integrated
var targetFolder = path.join( target, path.basename( source ) );
if ( !fs.existsSync( targetFolder ) ) {
fs.mkdirSync( targetFolder );
}
//copy
if ( fs.lstatSync( source ).isDirectory() ) {
files = fs.readdirSync( source );
files.forEach( function ( file ) {
var curSource = path.join( source, file );
if ( fs.lstatSync( curSource ).isDirectory() ) {
copyFolderRecursiveSync( curSource, targetFolder );
} else {
copyFileSync( curSource, targetFolder );
}
} );
}
}
答案 2 :(得分:43)
有些模块支持使用其内容复制文件夹。最受欢迎的是wrench
// Deep-copy an existing directory
wrench.copyDirSyncRecursive('directory_to_copy', 'location_where_copy_should_end_up');
另一种选择是node-fs-extra
fs.copy('/tmp/mydir', '/tmp/mynewdir', function (err) {
if (err) {
console.error(err);
} else {
console.log("success!");
}
}); //copies directory, even if it has subdirectories or files
答案 3 :(得分:21)
/**
* Look ma, it's cp -R.
* @param {string} src The path to the thing to copy.
* @param {string} dest The path to the new copy.
*/
var copyRecursiveSync = function(src, dest) {
var exists = fs.existsSync(src);
var stats = exists && fs.statSync(src);
var isDirectory = exists && stats.isDirectory();
if (exists && isDirectory) {
fs.mkdirSync(dest);
fs.readdirSync(src).forEach(function(childItemName) {
copyRecursiveSync(path.join(src, childItemName),
path.join(dest, childItemName));
});
} else {
fs.linkSync(src, dest);
}
};
答案 4 :(得分:15)
似乎ncp和wrench都不再维护。最好的选择可能是使用fs-extra
扳手的开发者指示用户使用fs-extra
,因为他已经弃用了自己的库
copySync 和 moveSync 都将复制和移动文件夹,即使它们具有文件或子文件夹,您也可以使用它轻松移动或复制文件
const fse = require('fs-extra');
const srcDir = `path/to/file`;
const destDir = `path/to/destination/directory`;
// To copy a folder or file
fse.copySync(srcDir, destDir, function (err) {
if (err) { ^
console.error(err); |___{ overwrite: true } // add if you want to replace existing folder or file with same name
} else {
console.log("success!");
}
});
OR
// To copy a folder or file
fse.moveSync(srcDir, destDir, function (err) {
if (err) { ^
console.error(err); |___{ overwrite: true } // add if you want to replace existing folder or file with same name
} else {
console.log("success!");
}
});
答案 5 :(得分:12)
对于linux / unix OS,您可以使用shell语法
const shell = require('child_process').execSync ;
const src= `/path/src`;
const dist= `/path/dist`;
shell(`mkdir -p ${dist}`);
shell(`cp -r ${src}/* ${dist}`);
那就是它!
答案 6 :(得分:9)
我创建了一个小工作示例,只需几步即可将源文件夹复制到另一个目标文件夹(基于使用ncp的@ shift66 answer):
步骤1 - 安装ncp模块:
npm install ncp --save
第2步 - 创建copy.js(将srcPath和destPath vars修改为您需要的任何内容):
var path = require('path');
var ncp = require('ncp').ncp;
ncp.limit = 16;
var srcPath = path.dirname(require.main.filename); //current folder
var destPath = '/path/to/destination/folder'; //Any destination folder
console.log('Copying files...');
ncp(srcPath, destPath, function (err) {
if (err) {
return console.error(err);
}
console.log('Copying files complete.');
});
第3步 - 运行
node copy.js
答案 7 :(得分:6)
fs-extra模块就像魅力一样。
安装fs-extra
$ npm install fs-extra
以下是将源目录复制到目标目录的程序。
// include fs-extra package
var fs = require("fs-extra");
var source = 'folderA'
var destination = 'folderB'
// copy source folder to destination
fs.copy(source, destination, function (err) {
if (err){
console.log('An error occured while copying the folder.')
return console.error(err)
}
console.log('Copy completed!')
});
参考
答案 8 :(得分:5)
如果目标目录已存在,则具有符号链接支持 +的那个不会抛出。
function copyFolderSync(from, to) {
try {
fs.mkdirSync(to);
} catch(e) {}
fs.readdirSync(from).forEach((element) => {
const stat = fs.lstatSync(path.join(from, element));
if (stat.isFile()) {
fs.copyFileSync(path.join(from, element), path.join(to, element));
} else if (stat.isSymbolicLink()) {
fs.symlinkSync(fs.readlinkSync(path.join(from, element)), path.join(to, element));
} else if (stat.isDirectory()) {
copyFolderSync(path.join(from, element), path.join(to, element));
}
});
}
答案 9 :(得分:3)
使用shelljs
npm i -D shelljs
const bash = require('shelljs');
bash.cp("-rf", "/path/to/source/folder", "/path/to/destination/folder");
答案 10 :(得分:3)
我在这里已经知道了很多答案,但是没有人以简单的方式回答。 关于fs-exra official documentation,您可以轻松完成
const fs = require('fs-extra')
// copy file
fs.copySync('/tmp/myfile', '/tmp/mynewfile')
// copy directory, even if it has subdirectories or files
fs.copySync('/tmp/mydir', '/tmp/mynewdir')
答案 11 :(得分:3)
@ mallikarjun-m谢谢!
fs-extra 做了这件事,如果你不提供回调,它甚至可以返回承诺! :)
const path = require('path')
const fs = require('fs-extra')
let source = path.resolve( __dirname, 'folderA')
let destination = path.resolve( __dirname, 'folderB')
fs.copy(source, destination)
.then(() => console.log('Copy completed!'))
.catch( err => {
console.log('An error occured while copying the folder.')
return console.error(err)
})
答案 12 :(得分:3)
由于我只是构建一个简单的节点脚本,我不希望脚本的用户需要导入一堆外部模块和依赖项,所以我戴上了思考上限并搜索了运行命令来自bash shell。
此node.js代码段以递归方式将名为node-webkit.app的文件夹复制到名为build的文件夹中:
child = exec("cp -r node-webkit.app build", function(error, stdout, stderr) {
sys.print("stdout: " + stdout);
sys.print("stderr: " + stderr);
if(error !== null) {
console.log("exec error: " + error);
} else {
}
});
感谢Lance Pollard at dzone让我入门。
上述代码段仅限于基于Unix的平台,如Mac OS和Linux,但类似的技术可能适用于Windows。
答案 13 :(得分:1)
这对于节点10来说非常容易。
const FSP = require('fs').promises;
async function copyDir(src,dest) {
const entries = await FSP.readdir(src,{withFileTypes:true});
await FSP.mkdir(dest);
for(let entry of entries) {
const srcPath = Path.join(src,entry.name);
const destPath = Path.join(dest,entry.name);
if(entry.isDirectory()) {
await copyDir(srcPath,destPath);
} else {
await FSP.copyFile(srcPath,destPath);
}
}
}
这假设dest
不存在。
答案 14 :(得分:1)
如果您使用的是Linux,并且性能不是问题,则可以使用exec
模块中的child_process
函数来执行Bash命令:
const { exec } = require('child_process');
exec('cp -r source dest', (error, stdout, stderr) => {...});
在某些情况下,我发现此解决方案比下载整个模块甚至使用fs
模块都更干净。
答案 15 :(得分:1)
提货时要小心。诸如copy-dir之类的某些软件包不支持复制长度超过0X1FFFFFE8个字符(约537 MB)的大型文件。
它将引发一些错误,例如:
buffer.js:630未捕获的错误:无法创建长度超过0x1fffffe8个字符的字符串
在我的一个项目中,我经历了类似的事情。最终,我不得不更改所使用的软件包并调整大量代码。我会说这不是一个非常愉快的经历。
如果需要多个源副本和多个目标副本,则可以使用better-copy并编写如下内容:
// Copy from multiple source into a directory
bCopy(['/path/to/your/folder1', '/path/to/some/file.txt'], '/path/to/destination/folder');
甚至:
// Copy from multiple source into multiple destination
bCopy(['/path/to/your/folder1', '/path/to/some/file.txt'], ['/path/to/destination/folder', '/path/to/another/folder']);
答案 16 :(得分:1)
此代码可以正常工作,以递归方式将任何文件夹复制到任何位置。仅限Windows。
var child=require("child_process");
function copySync(from,to){
from=from.replace(/\//gim,"\\");
to=to.replace(/\//gim,"\\");
child.exec("xcopy /y /q \""+from+"\\*\" \""+to+"\\\"");
}
完美适用于我的基于文本的游戏,用于创建新玩家。
答案 17 :(得分:0)
我尝试了fs-extra和copy-dir递归地复制文件夹。但我想要
所以我写了我自己的:
//node module for node 8.6+
var path=require("path");
var fs=require("fs");
function copyDirSync(src,dest,options){
var srcPath=path.resolve(src);
var destPath=path.resolve(dest);
if(path.relative(srcPath,destPath).charAt(0)!=".")
throw new Error("dest path must be out of src path");
var settings=Object.assign(Object.create(copyDirSync.options),options);
copyDirSync0(srcPath,destPath,settings);
function copyDirSync0(srcPath,destPath,settings){
var files=fs.readdirSync(srcPath);
if (!fs.existsSync(destPath)) {
fs.mkdirSync(destPath);
}else if(!fs.lstatSync(destPath).isDirectory()){
if(settings.overwrite)
throw new Error(`Cannot overwrite non-directory '${destPath}' with directory '${srcPath}'.`);
return;
}
files.forEach(function(filename){
var childSrcPath=path.join(srcPath,filename);
var childDestPath=path.join(destPath,filename);
var type=fs.lstatSync(childSrcPath).isDirectory()?"directory":"file";
if(!settings.filter(childSrcPath,type))
return;
if (type=="directory") {
copyDirSync0(childSrcPath,childDestPath,settings);
} else {
fs.copyFileSync(childSrcPath, childDestPath, settings.overwrite?0:fs.constants.COPYFILE_EXCL);
if(!settings.preserveFileDate)
fs.futimesSync(childDestPath,Date.now(),Date.now());
}
});
}
}
copyDirSync.options={
overwrite: true,
preserveFileDate: true,
filter: function(filepath,type){return true;}
};
和类似的函数mkdirs,可以替代mkdirp
function mkdirsSync(dest) {
var destPath=path.resolve(dest);
mkdirsSync0(destPath);
function mkdirsSync0(destPath){
var parentPath=path.dirname(destPath);
if(parentPath==destPath)
throw new Error(`cannot mkdir ${destPath}, invalid root`);
if (!fs.existsSync(destPath)) {
mkdirsSync0(parentPath);
fs.mkdirSync(destPath);
}else if(!fs.lstatSync(destPath).isDirectory()){
throw new Error(`cannot mkdir ${destPath}, a file already exists there`);
}
}
}
答案 18 :(得分:0)
ncp 会锁定文件描述符,并在尚未解锁时触发回调。
我建议改为使用recursive-copy模块。它支持事件,您可以肯定在副本结尾。
答案 19 :(得分:0)
如果要递归复制源目录的所有内容,则需要通过recursive
传递true
选项,并且try
catch
被fs-extra记录为sync
由于fs-extra
是fs
的完全替代,因此您无需导入基本模块
const fs = require('fs-extra');
let sourceDir = '/tmp/src_dir';
let destDir = '/tmp/dest_dir';
try {
fs.copySync(sourceDir, destDir, { recursive: true })
console.log('success!')
} catch (err) {
console.error(err)
}
答案 20 :(得分:-1)
解决此问题的最简单方法是仅使用“ fs”和“ Path”模块以及一些逻辑.....
如果要设置根文件夹中的所有文件,则使用新名称进行复制,只需设置版本号即可,即.......................“ var v = “您的目录名称””
在文件名前缀V内容中添加了文件名。
var fs = require('fs-extra');
var path = require('path');
var c = 0;
var i =0 ;
var v = "1.0.2";
var copyCounter = 0;
var directoryCounter = 0;
var directoryMakerCounter = 0;
var recursionCounter = -1;
var Flag = false;
var directoryPath = [] ;
var directoryName = [] ;
var directoryFileName = [];
var fileName;
var directoryNameStorer;
var dc = 0;
var route ;
if (!fs.existsSync(v)){
fs.mkdirSync(v);
}
var basePath = path.join(__dirname, v);
function walk(dir){
fs.readdir(dir, function(err, items) {
items.forEach(function(file){
file = path.resolve(dir, file);
fs.stat(file, function(err, stat){
if(stat && stat.isDirectory()){
directoryNameStorer = path.basename(file);
route = file;
route = route.replace("gd",v);
directoryFileName[directoryCounter] = route;
directoryPath[directoryCounter] = file;
directoryName[directoryCounter] = directoryNameStorer;
directoryCounter++;
dc++;
if (!fs.existsSync(basePath+"/"+directoryName[directoryMakerCounter])){
fs.mkdirSync(directoryFileName[directoryMakerCounter]);
directoryMakerCounter++;
}
}else{
fileName = path.basename(file);
if(recursionCounter >= 0){
fs.copyFileSync(file, directoryFileName[recursionCounter]+"/"+v+"_"+fileName, err => {
if(err) return console.error(err);
});
copyCounter++;
}else{
fs.copyFileSync(file, v+"/"+v+"_"+fileName, err => {
if(err) return console.error(err);
});
copyCounter++;
}
}
if(copyCounter + dc == items.length && directoryCounter > 0 && recursionCounter < directoryMakerCounter-1){
console.log("COPY COUNTER : "+copyCounter);
console.log("DC COUNTER : "+dc);
recursionCounter++;
dc = 0;
copyCounter = 0;
console.log("ITEM DOT LENGTH : "+items.length);
console.log("RECURSION COUNTER : "+recursionCounter);
console.log("DIRECOTRY MAKER COUNTER : "+directoryMakerCounter);
console.log(": START RECURSION : "+directoryPath[recursionCounter]);
walk(directoryPath[recursionCounter]); //recursive call to copy sub-folder
}
})
})
});
}
walk('./gd', function(err, data){ //Just Pass The Root Directory Which You Want to Copy
if(err) throw err;
console.log("done");
})
答案 21 :(得分:-1)
这是我的做法:
let fs = require('fs');
let path = require('path');
然后:
let filePath = //your FilePath
let fileList = []
var walkSync = function(filePath, filelist)
{
let files = fs.readdirSync(filePath);
filelist = filelist || [];
files.forEach(function(file)
{
if (fs.statSync(path.join(filePath, file)).isDirectory())
{
filelist = walkSync(path.join(filePath, file), filelist);
}
else
{
filelist.push(path.join(filePath, file));
}
});
// Ignore hidden files
filelist = filelist.filter(item => !(/(^|\/)\.[^\/\.]/g).test(item));
return filelist;
};
然后调用方法:
This.walkSync(filePath, fileList)
答案 22 :(得分:-1)
我编写了此函数,用于在目录之间递归地复制(copyFileSync)或移动(renameSync)文件:
//copy files
copyDirectoryRecursiveSync(sourceDir, targetDir);
//move files
copyDirectoryRecursiveSync(sourceDir, targetDir, true);
function copyDirectoryRecursiveSync(source, target, move) {
if (!fs.lstatSync(source).isDirectory()) return;
var operation = move ? fs.renameSync : fs.copyFileSync;
fs.readdirSync(source).forEach(function (itemName) {
var sourcePath = path.join(source, itemName);
var targetPath = path.join(target, itemName);
if (fs.lstatSync(sourcePath).isDirectory()) {
fs.mkdirSync(targetPath);
copyDirectoryRecursiveSync(sourcePath, targetDir);
}
else {
operation(sourcePath, targetPath);
}
});}
答案 23 :(得分:-1)
ncp
是cool
但是...... 你可能希望/应该宣传它的功能是super cool
。既然您正在使用它,请将其添加到tools
文件中以重复使用它。
以下是Async
的工作版本并使用Promises
。
index.js
const {copyFolder} = require('./tools/');
return copyFolder(
yourSourcePath,
yourDestinationPath
)
.then(() => {
console.log('-> Backup completed.')
}) .catch((err) => {
console.log("-> [ERR] Could not copy the folder: ", err);
})
tools.js
const ncp = require("ncp");
/**
* Promise Version of ncp.ncp()
*
* This function promisifies ncp.ncp().
* We take the asynchronous function ncp.ncp() with
* callback semantics and derive from it a new function with
* promise semantics.
*/
ncp.ncpAsync = function (sourcePath, destinationPath) {
return new Promise(function (resolve, reject) {
try {
ncp.ncp(sourcePath, destinationPath, function(err){
if (err) reject(err); else resolve();
});
} catch (err) {
reject(err);
}
});
};
/**
* Utility function to copy folders asynchronously using
* the Promise returned by ncp.ncp().
*/
const copyFolder = (sourcePath, destinationPath) => {
return ncp.ncpAsync(sourcePath, destinationPath, function (err) {
if (err) {
return console.error(err);
}
});
}
module.exports.copyFolder = copyFolder;