事件监听"/>
Node做excel导入学习到的finish与end事件监听
重点: finsih事件来自 stream.Writable
类,end 事件来自 stream.Readable
类。
背景
因为一个excel导入数据的需求,我用node通过使用formidable,fs,xlsx,mysql四个模块对上传的excel文件进行了解析,并将excel中的文件的内容导入到数据库中。
业务逻辑很简单,使用formidable模块接收前端上传的excel文件,使用fs模块将虚拟路径的临时文件转换为本地文件,再通过xlsx.parse()进行解析excel文件进行导入操作。
一切都是这样的理所应当,写完后一次测试立马成功。
带着小小的成就感,想连续多点几下,发现了个问题,xlsx.parse()偶尔会将excel文件中的内容解析为空。这是为什么呢?研究下代码。
代码
解析放在readStream的end事件监听回调中
// ...省略接收前端文件的代码部分// temPath在前面代码部分已定义并赋值let readStream=fs.createReadStream(tempPath); // 生成新的文件名let fileName = new Date().valueOf(),fileExt = FileUtil.getUploadFileExt(tempPath); // 获取文件后缀名// 若文件类型不符合要求返回if(fileExt==undefined||fileExt==""||(fileExt!="xls"&&fileExt!="xlsx")){fs.unlinkSync(tempPath);// 同步删除虚拟文件ctx.body = "文件类型有误";return resolve("抛出异常");}// 无论是什么格式的EXCEL都转换成xlsx格式进行保存curPath = DirPath+fileName+".xlsx";let writeStream=fs.createWriteStream(curPath); // 创建可写流readStream.pipe(writeStream); // 将可读流数据传入可写流// 文件写入完成监听readStream.on('end',async function(){fs.unlinkSync(tempPath);// 同步删除虚拟文件await insertList(curPath); // 数据插入操作fs.unlinkSync(curPath);// 同步删除本地文件ctx.body = "导入成功";resolve("完成");});// 插入数据
const insertList = async path=>{let table = xlsx.parse(path);// ....省略插入数据代码部分
}
当代码这样写的时候,会出现我在故事背景中的问题,会有某几次xlsx解析curPath对应的这个文件下的excel文件为空。
我从代码的执行顺序,是否在解析时候本地文件已经被删除等多个角度进行排查问题,进行了代码排查,结果都没找到原因。我就想是不是readStream触发end事件的时候writeStream中的数据还没有写完呢?或者说解析的时候还没有写好呢?于是我就去查询了下node文档中的stream模块里去查找writeable是否也有end事件,结果发现了文章开头部分的重点:finsih事件来自 stream.Writable
类,end 事件来自 stream.Readable
类。
将readStream.on("end")替换为writeStream.on("finish")后,这个问题就解决了。以后明白了,解析可读流文件还是要在writeStream的finish事件中进行。
更多推荐
Node做excel导入学习到的finish与end事件监听
发布评论