如何确保tar文件全部提取完成后再执行重命名操作?
问题
我通过tarFs将.tar文件内容提取到指定路径后,需要对提取出的6个文件执行重命名操作。在VS Code项目资源管理器中能看到所有文件,但运行时发现.on('finish')的执行早于tar文件提取完成,导致最后一个文件重命名失败。我曾将重命名代码包裹在setTimeout中临时解决问题,但这并非可靠方案;尝试监听close事件(code-2)也未生效。请问如何强制重命名操作在所有6个文件提取完成后执行?
code-1:
const tarStream = fs.createReadStream(pathToTarFileTobeExtracted); tarStream.pipe(tarFs.extract(untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2)) .on('finish', () => { setTimeout(() => { fs.renameSync( untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BANDS_COMPOSITE_NAME.description, untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[0]); fs.renameSync( untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BAND_1_NAME.description, untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[1]); fs.renameSync( untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BAND_2_NAME.description, untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[2]); fs.renameSync( untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BAND_3_NAME.description, untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[3]); fs.renameSync( untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BAND_4_NAME.description, untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[4]); fs.renameSync( untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BAND_5_NAME.description, untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[5]); console.log('xcx ***** old:', untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BAND_5_NAME.description) console.log('xcx ***** new:', untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[5]) }, 1000); })
code-2:
// 尝试解决问题的代码 const tarStream = fs.createReadStream(pathToTarFileTobeExtracted); const extractedStream = tarFs.extract(untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2); tarStream.pipe(extractedStream); extractedStream .on('close', () => { fs.renameSync( untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BANDS_COMPOSITE_NAME.description, untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[0]); fs.renameSync( untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BAND_1_NAME.description, untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[1]); fs.renameSync( untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BAND_2_NAME.description, untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[2]); fs.renameSync( untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BAND_3_NAME.description, untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[3]); fs.renameSync( untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BAND_4_NAME.description, untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[4]); fs.renameSync( untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BAND_5_NAME.description, untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[5]); console.log('xcx ***** old:', untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + SysConstants.CONST_BAND_5_NAME.description) console.log('xcx ***** new:', untarPath + outputFolderPerUntared + '\\' + outputFolderPerUntaredForTS2 + '\\' + titlesOfBandsAsGeoTIFFForTS2[5]) })
解决方案
方法1:监听tarFs的end事件(推荐)
tarFs的extract流真正代表所有文件提取完成的事件是end,而非finish或close:
finish是写入流接收完所有数据的事件,但此时操作系统可能还未将数据完全刷入磁盘;close是流底层资源关闭的事件,可能早于文件写入完成;end会在所有文件完全写入磁盘后触发。
修改后的代码:
const tarStream = fs.createReadStream(pathToTarFileTobeExtracted); const extractStream = tarFs.extract(`${untarPath}${outputFolderPerUntared}\\${outputFolderPerUntaredForTS2}`); tarStream.pipe(extractStream); extractStream.on('end', () => { const targetDir = `${untarPath}${outputFolderPerUntared}\\${outputFolderPerUntaredForTS2}\\`; fs.renameSync(targetDir + SysConstants.CONST_BANDS_COMPOSITE_NAME.description, targetDir + titlesOfBandsAsGeoTIFFForTS2[0]); fs.renameSync(targetDir + SysConstants.CONST_BAND_1_NAME.description, targetDir + titlesOfBandsAsGeoTIFFForTS2[1]); fs.renameSync(targetDir + SysConstants.CONST_BAND_2_NAME.description, targetDir + titlesOfBandsAsGeoTIFFForTS2[2]); fs.renameSync(targetDir + SysConstants.CONST_BAND_3_NAME.description, targetDir + titlesOfBandsAsGeoTIFFForTS2[3]); fs.renameSync(targetDir + SysConstants.CONST_BAND_4_NAME.description, targetDir + titlesOfBandsAsGeoTIFFForTS2[4]); fs.renameSync(targetDir + SysConstants.CONST_BAND_5_NAME.description, targetDir + titlesOfBandsAsGeoTIFFForTS2[5]); console.log('xcx ***** old:', targetDir + SysConstants.CONST_BAND_5_NAME.description); console.log('xcx ***** new:', targetDir + titlesOfBandsAsGeoTIFFForTS2[5]); });
方法2:用Promise封装(适配异步代码风格)
如果项目支持async/await,可以把提取操作封装为Promise,确保流程顺序:
const extractTar = (tarPath, outputDir) => { return new Promise((resolve, reject) => { const tarStream = fs.createReadStream(tarPath); const extractStream = tarFs.extract(outputDir); tarStream.pipe(extractStream); extractStream.on('end', resolve); extractStream.on('error', reject); tarStream.on('error', reject); }); }; // 执行逻辑 (async () => { try { const outputDir = `${untarPath}${outputFolderPerUntared}\\${outputFolderPerUntaredForTS2}`; await extractTar(pathToTarFileTobeExtracted, outputDir); // 执行重命名 const targetDir = `${outputDir}\\`; fs.renameSync(targetDir + SysConstants.CONST_BANDS_COMPOSITE_NAME.description, targetDir + titlesOfBandsAsGeoTIFFForTS2[0]); fs.renameSync(targetDir + SysConstants.CONST_BAND_1_NAME.description, targetDir + titlesOfBandsAsGeoTIFFForTS2[1]); fs.renameSync(targetDir + SysConstants.CONST_BAND_2_NAME.description, targetDir + titlesOfBandsAsGeoTIFFForTS2[2]); fs.renameSync(targetDir + SysConstants.CONST_BAND_3_NAME.description, targetDir + titlesOfBandsAsGeoTIFFForTS2[3]); fs.renameSync(targetDir + SysConstants.CONST_BAND_4_NAME.description, targetDir + titlesOfBandsAsGeoTIFFForTS2[4]); fs.renameSync(targetDir + SysConstants.CONST_BAND_5_NAME.description, targetDir + titlesOfBandsAsGeoTIFFForTS2[5]); console.log('重命名完成'); } catch (err) { console.error('提取或重命名失败:', err); } })();
内容的提问来源于stack exchange,提问作者Amr
相关产品推荐
相关产品推荐

