首页 > 解决方案 > 如何在遍历一系列目录的循环中使用异步 readdir 函数?

问题描述

我正在归档来自多个目录的某些文本文件。因此,首先,我在一个文件夹中进行迭代,该文件夹为我提供了 folderPath,这个 folderPath 可以包含许多文件(txt、pdf 等)并且有多个文件夹路径,我对 folderPath 使用异步 readdir 并将这些单独的文件附加到归档器,然后最后关闭。如果我在文件夹循环结束之前执行 archive.finalize ,它不会在 zip 中生成所需数量的 txt 文件,而只是生成初始文件,这很明显。如果我将 archive.finalize 保留在第 2 行,则会向我抛出一个错误,如下所示的目录结构。有人可以在这方面提供帮助吗?

目录结构如下:

主文件夹/文件夹 1 主文件夹/文件夹 2

主文件夹/文件夹 1/sometext.txt 主文件夹/文件夹 1/someanothertext.txt

主文件夹/文件夹 2/sometext.txt 主文件夹/文件夹 2/someanothertext.txt

现在我想将其压缩为:

Outuput.zip 包含 -> folder1 和 folder2 以及各自的 txt 文件。使用同步函数到 readdir(readdirsync) 时,我能够实现它,但是使用异步,我面临一些回调问题。

错误 :

ArchiverError: queue closed
    at Archiver.file (C:\Users\Workspace\code\node_modules\archiver\lib\core.js:692:24)
    at C:\Users\Workspace\current_code_snippet
    at Array.forEach (<anonymous>)
    at C:\Users\current_code_snippet_ line 3 as specified in code snippet
    at FSReqCallback.oncomplete (fs.js:156:23) {
  code: 'QUEUECLOSED',
  data: undefined
}

代码 :

this.children.forEach((value, _index, _array) => {
    const folderPath = path.join(basePath, value);
    fs.readdir(folderPath, (err, fileNames) => {
          if (err){
              throw err;
          }
          else {
            fileNames.forEach(file => {  // line 3
              if (outputType === ".txt") {
                  const filePath = path.join(basePath, value, file);
                  archive.file(filePath, { name: `${value}/${file}` }); // file is saved as value/file inside parent zip
              }
            })
          }
    })
    archive.finalize(); // line 1
});
archive.finalize(); // line 2

标签: javascriptnode.jstypescriptarchive

解决方案


我会将 fs 调用包装成 Promise。这使得等待操作成为可能,并且降低了代码的一些复杂性。

请注意,forEach循环不适用于async, await

const children = ["path_0", "path_1", "path_2", "path_3"];

// mock fs / async action
const fs = {
    readdir: (path, error, success) => {
        setTimeout(() => {
            success(["file_0", "file_1", "file_2"]);
        }, Math.random() * 1000);
    }
}

// function I would add to make the process simpler
const readFiles = (path) => {
    return new Promise(res => {
        fs.readdir(path, () => {}, (s) => {
            res(s);
        });
    });
}
// start helper as async
const start = async() => {
    // first await all files to be added to the archive
    await Promise.all(children.map(async child => {
        const files = await readFiles();
        // loop to add all files to the zip
        // archive.file(filePath, { name: `${value}/${file}` });
        console.log(child, files);
    }));
    // then archive all files
    // archive.finalize();
    console.log("finalize archive");
}
start();


推荐阅读