为什么Node.js中fs.copyFileSync()复制文件得到空白文件?
根因分析
fs.createReadStream 是异步API,你绑定的readable事件回调会在事件循环的异步阶段执行,而你紧随其后写的fs.copyFileSync是同步API,会在当前同步执行栈立刻运行。
这时候流还没有完成读取,也没有把所有偏移后的ID写入FILE_PATH_TO_POST_SHIFT_IDENTIFIERS临时文件,你复制时源文件还是空的,自然得到空白的目标文件。
你交换源和目标路径后复制有内容,是因为目标路径对应的文件是你之前用fs.writeFileSync同步写完的,本身就有有效内容。
修复方法
- 首先每次处理前清空临时偏移ID文件,避免残留旧内容干扰
- 将文件复制、数据库更新、页面跳转逻辑全部放到可读流的
end事件回调中,等流读取、写入完全完成后再执行后续操作
修复后的核心代码片段如下:
/* POST delete post */ router.post("/", function(req, res, next) { Post.findOneAndRemove({postId: sessionStorage.getItem("deleteIdentifier")}, function(err, post) { if (err) { console.log(err) } else { console.log("Removed post: " + post) } }) // Get the file contents then find and replace identifier. var postIdentifiers = fileSystem.readFileSync(constantVariable.FILE_PATH_POST_IDENTIFIERS, {encoding: "utf-8"}) var newValue = postIdentifiers.replace(sessionStorage.getItem("deleteIdentifier").toString(), "") // Write the replacement value to the file. fileSystem.writeFileSync(constantVariable.FILE_PATH_POST_IDENTIFIERS, newValue) // 每次先清空临时文件,避免旧内容残留 fileSystem.writeFileSync(constantVariable.FILE_PATH_TO_POST_SHIFT_IDENTIFIERS, '') // Write all the contents from postIds.txt to postShiftIds.txt - 1. var readable = fileSystem.createReadStream(constantVariable.FILE_PATH_POST_IDENTIFIERS, {encoding: "utf-8"}) readable.on("readable", function() { var id = "" var parsedId = 0 var shiftedId = 0 while ((id = readable.read(1)) !== null) { parsedId = parseInt(id) if (parsedId !== 0) { parsedId -= 1 shiftedId = parsedId } // Write the shifted identifier to postShiftIds.txt - 1. fileSystem.appendFileSync(constantVariable.FILE_PATH_TO_POST_SHIFT_IDENTIFIERS, shiftedId.toString()) } }) // 等流读取写入完成后再执行后续逻辑 readable.on('end', function() { // Copy the shifted identifiers to the original file. fileSystem.copyFileSync(constantVariable.FILE_PATH_TO_POST_SHIFT_IDENTIFIERS, constantVariable.FILE_PATH_POST_IDENTIFIERS) // Shift all the post identifiers down one. Post.find({}).exec(function(err, posts) { if (err) { console.log(err) } else { var package = {} posts.forEach((post) => { // Dont subtract the first id. if (post.postId === 0) { package = { postId: post.postId, emailId: post.emailId, postTitle: post.postTitle, postMessage: post.postMessage } } else { package = { postId: post.postId - 1, emailId: post.emailId, postTitle: post.postTitle, postMessage: post.postMessage } } Post.findOneAndUpdate({postId: post.postId}, package, {new: true}, function(err, post) { if (err) { console.log(err) } else { console.log("Shifted index: ", post) } }) }) } }) res.redirect("allPosts") }) })
额外优化建议
你当前的ID读取逻辑是每次读取1个字符,仅支持个位数的postId,当postId超过9变成两位数及以上时,会把ID拆成单个字符处理导致逻辑错误。建议你将ID按行存储,读取时按换行符拆分处理,适配多位数ID的场景。
内容的提问来源于stack exchange,提问作者user15746554
相关产品推荐
相关产品推荐

