遍历目录树?"/>
如何并行遍历目录树?
首先,我想描述问题:我有一个目录树(深度= 3),其中包含几个目录和文件。其中一些文件具有.txt扩展名,而某些文件具有.mp4。我只想复制新目录中具有与源目录相同层次结构的.mp4文件(换句话说,我不想将所有mp4文件复制到一个文件夹中,我想按原样复制所有目录,然后复制mp4文件)。问题是:如何不按顺序而是并行复制这些文件?这是我的代码:
const fs = require('fs');
const path = require('path');
const { promisify } = require('util');
const sourceDir = process.argv[2];
const stat = promisify(fs.stat);
const copy = promisify(fs.copyFile);
const mkdir = promisify(fs.mkdir);
const readdir = promisify(fs.readdir);
const targetDir = path.join(__dirname, 'only-mp4');
// creating root folder, all files will be copied here
(async () => {
await mkdir(targetDir);
})();
const copyMediaFiles = async (node) => {
try {
const stats = await stat(node);
if (stats.isDirectory()) {
let children = await readdir(node);
// constructing new paths
children = children.map((child) => path.join(node, child));
// "copying" file hierarchy (basically just recreating same file hierarchy in target directory)
children.forEach((child) => {
const courseDirs = child.split('/').slice(4, 7).join('/');
mkdir(path.join(targetDir, courseDirs), { recursive: true });
});
// running this function for all children recursively in parallel
const promises = children.map(copyMediaFiles);
await Promise.all(promises);
}
const ext = path.extname(node);
const filename = path.basename(node);
// if file extension == mp4 then copy that file in target directory
if (ext === '.mp4') {
await copy(
node,
path.join(
targetDir,
path.dirname(node).split('/').slice(4).join('/'),
filename
)
);
console.log('File copied: ', filename);
}
return;
} catch (error) {
console.log(error);
}
};
copyMediaFiles(sourceDir).then(() => console.log('All mp4 files copied'));
是的,它正在工作,但是我不确定我做对了吗。有什么建议吗?我在这里做错了什么?而且我不确定我是否正确遍历了这棵树。
回答如下:两个问题:
copyMediaFiles
的第一个调用将在第一个mkdir
承诺解决之前发生。这是有风险的,因为您实际上可能在创建目标目录之前尝试访问它。如果仅将copyMediaFiles
的呼叫放在async
IIFE内,那么您就没有这种风险:(async () => { await mkdir(targetDir); await copyMediaFiles(sourceDir); console.log('All mp4 files copied'); })();
mkdir
的第二次调用未捕获其返回的承诺,因此也发生了类似的风险。
可能会进一步改善“压缩”:
您的目标是最大程度地减少JavaScript的空闲时间(等待承诺的解决),并且可以通过最大化待处理的承诺的数量来做到这一点。
因此,最好在相应的copyMediaFiles
承诺得到解决后立即发起对mkdir
的调用,而不是在进行该调用之前先不发起所有同级目录的创建:
const children = await readdir(node);
const promises = children.map(async child => {
child = path.join(node, child);
const courseDirs = child.split('/').slice(4, 7).join('/');
await mkdir(path.join(targetDir, courseDirs), { recursive: true });
await copyMediaFiles(child);
});
await Promise.all(promises);
使用此代码,您可能会在创建所有同级目录之前启动copyMediaFiles
调用。如果您的目录具有较高的分支因子,则意味着您将获得更长的待处理承诺列表,这可能对整体性能有所帮助。
全部取决于基础API管理并发的程度。
更多推荐
如何并行遍历目录树?
发布评论