Node.js | Excel文件处理最佳实践:拆分和导出

540 阅读4分钟

如何使用nodejs快速拆分excel文件

业务场景

最近在进行数据迁移时,领导给我安排了几十个几万条数据的excel文件进行迁移,但是所迁移的系统不支持过于大的excel文件解析,需要将excel拆分为多个较小的excel文件,才能上传。

所用技术

exceljs, nodejs, readline, fs

使用方法及实现效果

  1. 首先下载代码并配置好nodejs环境 (搜索nodejs环境配置)
  2. 使用编辑器或使用自带终端,进入代码文件夹,执行npm i命令
  3. 将需要分割的文件放置在input文件夹内,一次只能分割一个
  4. 执行npm run start,输入分割大小,等待代码执行
  5. 分割好的excel文件存在output文件夹中

文件目录

Snipaste_2024-08-20_18-08-07.png
使用方法,执行npm run start

Snipaste_2024-08-20_18-08-16.png

执行完毕

Snipaste_2024-08-20_18-08-27.png

Exceljs

当涉及到处理 Excel 文件时,ExcelJS 是一个非常有用的 JavaScript 库。它可以在 Node.js 和浏览器环境中实现代码层面的 Excel 编辑功能。包括创建、导出、读取、修改内容等 功能。

Exceljs可以通过调用方法编辑excel文件的内容,操作单元包括了工作表、单元行、单元列以及单元格,不仅可以设置单元格的值还可以设置格式样式。这意味着可以通过编程方式生成复杂的报表和数据表格。

除了数据,ExcelJS 还允许你创建和修改 Excel 文件中的图表和图形。你可以设置图表的类型、数据范围、标题和样式。这使得你可以在报表中添加可视化的图表,以更好地呈现数据。

ExcelJS 提供了丰富的样式和格式选项。你可以设置单元格、行、列和工作表的样式,包括字体、颜色、边框、对齐方式等。这使得你可以自定义 Excel 文件的外观,使其符合你的品牌和设计要求。

如果你需要在单元格中进行计算,ExcelJS 也支持设置和计算公式。你可以使用内置的 Excel 函数和运算符来创建复杂的公式,并在计算时获取结果。

ExcelJS 还允许你在 Excel 文件中插入图片和图表,并设置其位置、大小和样式。这使得你可以在报表中添加图片和图表,以更好地展示数据和信息。

exceljs/exceljs: Excel Workbook Manager (github.com)

具体代码实现

我们需要实现读取一个大体积的excel文件,同时对文件内容进行分割,之后导出为较小的excel文件。

读取excel文件

//文件路径
let excelfile = "test.xlsx";
//获取待分割excel文件路径
const filenames = fs.readdirSync('./input')
if (filenames)
    excelfile = filenames[0]
//文件入口
let url = './input/' + excelfilees[0]  
// 初始化
const workbook = new ExcelJS.Workbook();
workbook.xlsx.readFile(url).then(function () {
   var worksheet = workbook.getWorksheet(1); //获取第一个worksheet
});
  • 首先使用fs读取input文件夹下的大体积excel文件,设置好文件url
  • 初始化exceljs, 创建workbook,同时使用readFile方法读取目标文件
  • 使用getWorksheet获取excel文件的内容,默认读取第一个工作表
  • 此时worksheet即为我们需要分割的excel文件

获取数据并设置表头


workbook.xlsx.readFile(url).then(function () {
    var worksheet = workbook.getWorksheet(1); //获取第一个worksheet
    let tableHead
    let data = []
    worksheet.eachRow(function (row, rowNumber) {
            //获取表头
        if (rowNumber == 1)
            tableHead = row.values.slice(1)
        else
            data.push(row.values.slice(1))
    });
        const arr = sliceArray(data, fileSize)
        output(arr, tableHead)
});
  • 获取完excel之后,使用eachRow方法读取数据
  • 判断是否为表头,并保存表头数据,slice(1) --> 去除null数据
  • 存储所有的数据

分割数据

遍历整个数据并按照文件大小进行分割

//分割
function sliceArray(array, size) {
    var result = [];
    for (var i = 0; i < Math.ceil(array.length / size); i++) {
        var start = i * size;
        var end = start + size;
        result.push(array.slice(start, end));
    }
    return result;
}

导出

使用exceljs创建一个新的workbook,并使用addRow方法添加表头和数据

最后使用writeFile方法导出数据

// 导出
function output(data, head) {
    data.forEach(async (i, index) => {
        // 创建工作簿
        const _workbook = new ExcelJS.Workbook();
        // 添加工作表
        const _sheet1 = _workbook.addWorksheet("sheet1");
        _sheet1.addRow(head)
        _sheet1.addRows(i)
        // 导出表格
        let url = excelfile.split('.')
        url[0] = url[0] + index
        await _workbook.xlsx.writeFile(`./output/${url.join('.')}`)
    })

}

优化

为了动态的接受用户输入的文件大小,使用readline读取用户输入的分割大小进行分割。

将整个分割逻辑封装到start函数中,判断输入参数后执行分割。

//获取分割大小
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});
// ask user for the fileSize
let fileSize = 1000
rl.question(`What is the file size you need?\n`, (size) => {
    if (isNaN(size))
        console.log('输入数据有误,请输入数字')
    else {
        fileSize = +size
        if(fileSize <= 0 || !Number.isInteger(fileSize)){
            console.log('请输入一个正整数')
            rl.close();
            return
        }
        console.log('正在处理数据...')
        start()
    }
    rl.close();
});