【发布时间】:2022-11-04 19:03:40
【问题描述】:
我试图了解哪种设置最适合执行以下操作:
- 逐行读取 CSV 文件
- 使用行数据作为复杂函数的输入,该函数最终输出一个文件(每行一个文件)
- 整个过程完成后,我需要压缩步骤 2 中生成的所有文件
我的目标:能够处理大文件的快速且可扩展的解决方案
我已经使用两种方法实现了第 2 步,我想知道什么是最好的以及为什么(或者是否有其他更好的方法)
步骤1
这很简单,我依赖CSV Parser - async iterator API:
async function* loadCsvFile(filepath, params = {}) { try { const parameters = { ...csvParametersDefault, ...params, }; const inputStream = fs.createReadStream(filepath); const csvParser = parse(parameters); const parser = inputStream.pipe(csvParser) for await (const line of parser) { yield line; } } catch (err) { throw new Error("error while reading csv file: " + err.message); } }第2步
选项1
等待每一行的长操作
handleCsvLine:// step 1 const csvIterator = loadCsvFile(filePath, options); // step 2 let counter = 0; for await (const row of csvIterator) { await handleCvsLine( row, ); counter++; if (counter % 50 === 0) { logger.debug(`Processed label ${counter}`); } } // step 3 zipFolder(folderPath);临
- 很高兴看到文件一个接一个地生成
- 因为它等待操作结束,所以我可以很好地显示进度
缺点
- 它等待每个操作,我可以更快吗?
选项 2
将长操作
handleCsvLine推入一个数组,然后在循环之后执行Promise.all:// step 1 const csvIterator = loadCsvFile(filePath, options); // step 2 let counter = 0; const promises = []; for await (const row of csvIterator) { promises.push(handleCvsLine(row)); counter++; if (counter % 50 === 0) { logger.debug(`Processed label ${counter}`); } } await Promise.all(promises); // step 3 zipFolder(folderPath);临
- 我不等待,所以它应该更快,不是吗?
缺点
- 因为它不等待,所以 for 循环非常快,但最后有很长的等待时间(又名,糟糕的进度体验)
第 3 步
一个简单的步骤,我使用archiver 库创建文件夹的 zip,我在其中保存了步骤 2 中的文件:
function zipFolder(folderPath, globPath, outputFolder, outputName, logger) { return new Promise((resolve, reject) => { // create a file to stream archive data to. const stream = fs.createWriteStream(path.join(outputFolder, outputName)); const archive = archiver("zip", { zlib: { level: 9 }, // Sets the compression level. }); archive.glob(globPath, { cwd: folderPath }); // good practice to catch warnings (ie stat failures and other non-blocking errors) archive.on("warning", function (err) { if (err.code === "ENOENT") { logger.warning(err); } else { logger.error(err); reject(err); } }); // good practice to catch this error explicitly archive.on("error", function (err) { logger.error(err); reject(err); }); // pipe archive data to the file archive.pipe(stream); // listen for all archive data to be written // 'close' event is fired only when a file descriptor is involved stream.on("close", function () { resolve(); }); archive.finalize(); }); }
【问题讨论】:
标签: node.js asynchronous async-await