使用JavaScript读取含多类型数据的Excel文件时出现浮点数精度错误的技术求助
解决Excel小数读取精度问题及数据对比方案
首先,你遇到的这个浮点数精度问题其实是二进制浮点数的固有特性——很多十进制小数没法用二进制精确表示,Excel里看起来是0.15,但实际存储的是它的二进制近似值,读取工具只是把这个近似值暴露出来了。下面给你几个具体的解决思路,以及数据对比的实现方法:
一、优化xlsx-js的读取配置
你可以在sheet_to_json的时候添加数值格式化的选项,强制把小数按指定精度转换,避免显示冗余的小数位:
this.data = XLSX.utils.sheet_to_json(ws, { header: 1, raw: false, // 自定义单元格格式化逻辑 cellFormat: (cell) => { if (typeof cell.v === 'number' && !Number.isInteger(cell.v)) { // 根据你的实际需求保留小数位数,这里以2位为例 return Number(cell.v.toFixed(2)); } return cell.v; } });
如果上面的cellFormat不生效,也可以在读取完成后遍历数据统一处理:
this.data = this.data.map(row => { return row.map(cell => { if (typeof cell === 'number' && !Number.isInteger(cell)) { return Number(cell.toFixed(2)); } return cell; }); });
二、ExcelJS的精确读取方案
如果再尝试ExcelJS,可以利用它的单元格格式信息来还原精确值:
const workbook = new ExcelJS.Workbook(); await workbook.xlsx.load(buffer); const worksheet = workbook.getWorksheet(2); // 注意Sheet索引从1开始 this.data = []; worksheet.eachRow({ includeEmpty: false }, (row) => { const rowData = row.values.map(cell => { if (cell?.type === 'number') { // 读取Excel设置的单元格格式,比如"0.00" const decimalPlaces = cell.numFmt?.split('.')[1]?.length || 2; return Number(cell.value.toFixed(decimalPlaces)); } return cell?.value || cell; }); this.data.push(rowData); });
三、数据对比的实现技巧
对比数据库数据和Excel数据时,不能直接用===比较小数,需要加入精度容错:
// 定义精度比较函数,默认容错1e-6 function areNumbersEqual(num1, num2, precision = 1e-6) { return Math.abs(num1 - num2) < precision; } // 对比单行数据 function compareRows(dbRow, excelRow) { if (dbRow.length !== excelRow.length) return false; return dbRow.every((dbCell, index) => { const excelCell = excelRow[index]; // 处理小数的情况 if (typeof dbCell === 'number' && typeof excelCell === 'number') { return areNumbersEqual(dbCell, excelCell); } // 字符串、Unicode等类型直接全等比较 return dbCell === excelCell; }); } // 遍历所有行找出差异 const differences = []; this.data.forEach((excelRow, rowIndex) => { const dbRow = yourDbData[rowIndex]; // 替换为你的数据库行数据 if (!compareRows(dbRow, excelRow)) { differences.push({ rowNumber: rowIndex + 1, // 对应Excel的行号(从1开始) databaseData: dbRow, excelData: excelRow }); } }); console.log('差异数据:', differences);
额外提示
如果Excel里的小数是精确的十进制值(比如金额),建议在Excel里把单元格格式设置为「文本」或者「会计专用」,这样读取工具会直接读取字符串形式的数值,转成Number后就不会有精度问题了。
内容的提问来源于stack exchange,提问作者nandhini venkateshwaran
相关产品推荐
相关产品推荐

