是否有一种更简单的方法来复制文件夹及其所有内容,而无需手动执行一系列的fs。readir, fs。readfile, fs。writefile递归?
我只是想知道我是否错过了一个函数,理想情况下是这样工作的:
fs.copy("/path/to/source/folder", "/path/to/destination/folder");
关于这个历史问题。注意fs。Cp和fs。cpSync可以递归复制文件夹,在Node v16+中可用
是否有一种更简单的方法来复制文件夹及其所有内容,而无需手动执行一系列的fs。readir, fs。readfile, fs。writefile递归?
我只是想知道我是否错过了一个函数,理想情况下是这样工作的:
fs.copy("/path/to/source/folder", "/path/to/destination/folder");
关于这个历史问题。注意fs。Cp和fs。cpSync可以递归复制文件夹,在Node v16+中可用
当前回答
这是我个人的做法:
function copyFolderSync(from, to) {
fs.mkdirSync(to);
fs.readdirSync(from).forEach(element => {
if (fs.lstatSync(path.join(from, element)).isFile()) {
fs.copyFileSync(path.join(from, element), path.join(to, element));
} else {
copyFolderSync(path.join(from, element), path.join(to, element));
}
});
}
它适用于文件夹和文件。
其他回答
我尝试了fs-extra和copy-dir来递归地复制文件夹。但我希望它能
正常工作(copy-dir抛出一个不合理的错误) 在过滤器中提供两个参数:filepath和filetype (fs-extra不告诉文件类型) 有从目录到子目录的检查和从目录到文件的检查吗
所以我自己写了:
// Node.js module for Node.js 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`);
}
}
}
下面是一个递归复制目录及其内容到另一个目录的函数:
const fs = require("fs")
const path = require("path")
/**
* 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 (isDirectory) {
fs.mkdirSync(dest);
fs.readdirSync(src).forEach(function(childItemName) {
copyRecursiveSync(path.join(src, childItemName),
path.join(dest, childItemName));
});
} else {
fs.copyFileSync(src, dest);
}
};
这段代码可以很好地工作,递归地将任何文件夹复制到任何位置。但它只适用于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 + "\\\"");
}
它非常适合我的基于文本的游戏去创造新玩家。
这是我解决这个问题的方法,没有任何额外的模块。只使用内置的fs和path模块。
注意:这使用fs的读/写函数,所以它不复制任何元数据(创建时间等)。从Node.js 8.5开始,有一个copyFileSync函数可用,它调用操作系统复制函数,因此也复制元数据。我还没有测试它们,但它应该可以替换它们。(见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 );
}
} );
}
}
挑选包裹时要小心。有些包(如copy-dir)不支持复制长度超过0X1FFFFFE8个字符(约537 MB)的大文件。
它会抛出一些错误,比如:
buffer.js:630 Uncaught Error:不能创建大于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']);