最新消息: 电脑我帮您提供丰富的电脑知识,编程学习,软件下载,win7系统下载。

如何并行遍历目录树?

IT培训 admin 14浏览 0评论

如何并行遍历目录树?

首先,我想描述问题:我有一个目录树(深度= 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管理并发的程度。

如何并行遍历目录树?

首先,我想描述问题:我有一个目录树(深度= 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管理并发的程度。

与本文相关的文章

发布评论

评论列表 (0)

  1. 暂无评论