如何在遍历一系列目录的循环中使用异步 readdir 函数?
How to use async readdir function inside a loop iterating over series of directories?
我正在从多个目录中归档某些文本文件。所以首先,我在一个文件夹内迭代,它给我 folderPath 并且这个 folderPath 可以包含许多文件(txt、pdf 等)并且有多个文件夹路径,我正在为 folderPath 使用异步 readdir 并将这些单独的文件附加到归档器,然后最后关闭。如果我在文件夹循环结束之前执行 archive.finalize,它不会在 zip 中生成所需数量的 txt 文件,而只是初始文件,这很明显。如果我在第 2 行保留 archive.finalize,它会抛出一个错误,如目录结构下方所述。有人可以在这方面提供帮助吗?
Directory structure is like:
mainfolder/folder1 mainfolder/folder2
mainfolder/folder1/sometext.txt mainfolder/folder1/someanothertext.txt
mainfolder/folder2/sometext.txt mainfolder/folder2/someanothertext.txt
Now I want to zip it as:
Outuput.zip which contains -> folder1 and folder2 with respective txt
files. I was able to achieve it when using sync function to readdir(readdirsync),
but with async, I am facing some callback issue.
错误:
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
我会将 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();
我正在从多个目录中归档某些文本文件。所以首先,我在一个文件夹内迭代,它给我 folderPath 并且这个 folderPath 可以包含许多文件(txt、pdf 等)并且有多个文件夹路径,我正在为 folderPath 使用异步 readdir 并将这些单独的文件附加到归档器,然后最后关闭。如果我在文件夹循环结束之前执行 archive.finalize,它不会在 zip 中生成所需数量的 txt 文件,而只是初始文件,这很明显。如果我在第 2 行保留 archive.finalize,它会抛出一个错误,如目录结构下方所述。有人可以在这方面提供帮助吗?
Directory structure is like:
mainfolder/folder1 mainfolder/folder2
mainfolder/folder1/sometext.txt mainfolder/folder1/someanothertext.txt
mainfolder/folder2/sometext.txt mainfolder/folder2/someanothertext.txt
Now I want to zip it as:
Outuput.zip which contains -> folder1 and folder2 with respective txt files. I was able to achieve it when using sync function to readdir(readdirsync), but with async, I am facing some callback issue.
错误:
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
我会将 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();