需求
在上一篇推送,我提到了这样一个需求:
A上传一份任务文件(文件类型不限)到网站上,B看到后下载文件,按照文件里的要求完成任务之后,B要把任务完成情况汇总到一个Excel文档中,上传到网站上(此时只能上传xls格式的excel文档),然后网站在后台对这份Excel文档的数据进行处理,生成一份新的Excel文档。
所以,我写了一篇分享《node.js实现上传与下载文件》。而这次,我想针对这个需求分享下:node.js读写excel文件。
实现
思路
有哪些外部模块支持读写Excel
引入模块
编写业务逻辑函数
支持读写Excel的node.js模块
上npm搜索过,发现支持读写excel文件的模块有很多,但是都各有缺陷,有些仅支持xls/xlsx的一种格式,有些仅支持读取数据,有些仅支持导出文件。例如:
node-xlsx: 基于Node.js解析excel文件数据及生成excel文件,仅支持xlsx格式文件;
excel-parser: 基于Node.js解析excel文件数据,支持xls及xlsx格式文件;
excel-export : 基于Node.js将数据生成导出excel文件,生成文件格式为xlsx;
node-xlrd: 基于node.js从excel文件中提取数据,仅支持xls格式文件。
在我的项目中,我使用的是noe-xlrd模块及excel-export模块,用于提取上传上来的excel文件里的数据,以及生成新的excel文件。
引入模块
编辑项目工程里的package.json文件:
{
"name": "appname",
"virsion": "0.0.1",
"dependencies": {
"express": "~4.8.8",
"node-xlrd": "0.2.4",
"excel-export": "0.4.1"
}
}
执行node命令安装模块
npm install
编写业务逻辑函数
1.解析excel文件数据
var xl = require('node-xlrd');
exports.read = function(req, res, next){
var path = 'test.xls';
var datas = [];
xl.open(path, function(err,bk){
if(err) {console.log(err.name, err.message); return;}
var shtCount = bk.sheet.count;
for(var sIdx = 0; sIdx < shtCount; sIdx++ ){
console.log('sheet "%d" ', sIdx);
console.log(' check loaded : %s', bk.sheet.loaded(sIdx) );
var sht = bk.sheets[sIdx],
rCount = sht.row.count,
cCount = sht.column.count;
console.log(' name = %s; index = %d; rowCount = %d; columnCount = %d', sht.name, sIdx, rCount, cCount);
for(var rIdx = 0; rIdx < rCount; rIdx++){ // rIdx:行数;cIdx:列数
var data = [];
for(var cIdx = 0; cIdx < cCount; cIdx++){
try{
data[cIdx] = sht.cell(rIdx,cIdx);
console.log(' cell : row = %d, col = %d, value = "%s"', rIdx, cIdx, sht.cell(rIdx,cIdx));
}catch(e){
console.log(e.message);
}
}
datas[rIdx] = data;
}
}
req.datas = datas;
});
};
解析出来的数据有不同的数据类型:string、number。可以用 typeof sht.cell(rIdx,cIdx)
检测数据类型。
2.将处理后的数据生成新的excel文件
var excelPort = require('excel-export');
exports.write = function(req, res, next){
var datas = req.datas;
var conf = {};
var filename = 'filename'; //只支持字母和数字命名
conf.cols = [
{caption:'名称', type:'string', width:20},
{caption:'简介', type:'string', width:40},
{caption:'报酬', type:'string', width:20},
{caption:'时间', type:'date', width:40},
{caption:'人员', type:'string', width:30},
{caption:'编号', type:'string', width:30},
{caption:'金额', type:'number', width:30},
{caption:'手机号', type:'string', width:30}
];
var array = [];
array[0] = [
datas[0][0],
datas[0][1],
datas[0][2],
datas[0][3],
datas[0][4],
datas[0][5],
datas[0][6],
datas[0][7]
];
conf.rows = array[0];
var result = excelPort.execute(conf);
var random = Math.floor(Math.random()*10000+0);
var uploadDir = 'public/upload/pay/';
var filePath = uploadDir + filename + random + ".xlsx";
fs.writeFile(filePath, result, 'binary',function(err){
if(err){
console.log(err);
}
});
}
caption设置首行各单元格内容,type设置的是每一列的数据类型,width设置单元格大小。
rows 赋值的是每一行的数据,每个数据都要与所在列所设置的数据格式一致,否则会报错,生成后的表格该单元格会显示NaN。
总结
在读取解析完excel文件里的数据后,一般要根据项目需求对数据进行处理。进行数据处理时,要格外注意所解析到的数据的数据类型,以及要生成新的表格时,处理后的数据的数据类型是否符合所设置的数据类型。否则,bug不断….