基于 JNI + Rust 实现一种高性能 Excel 导出方案(上篇)

每个不曾起舞的日子,都是对生命的辜负。
——尼采

一、背景:Web 导出 Excel 的场景

Web 导出 Excel 功能在数据处理、分析和共享方面提供了极大的便利,是许多 Web 应用程序中的重要功能。以下是一些典型的场景:

  1. 数据报表导出:在企业管理系统(如ERP、CRM)中,用户经常需要将系统中的数据生成报表并导出为 Excel 文件,以便进行进一步的分析和处理。例如,销售人员可以导出月度销售报告,财务人员可以导出财务报表。
  2. 数据备份与归档:用户可能需要定期将系统中的数据导出为 Excel 文件进行备份或归档,以确保数据安全和可追溯性。例如,学校的学生成绩记录、医院的病人就诊记录等。
  3. 数据共享与交流:在团队协作中,成员之间需要共享数据,Excel 文件是一种方便的格式,可以在不同的软件和平台之间轻松传递和查看。例如,项目经理可以导出项目进度数据,与团队成员或客户分享。
  4. 自定义数据分析:用户可能希望对系统中的数据进行自定义分析,而 Excel 提供了强大的数据处理和分析功能,如透视表、图表等。例如,市场分析人员可以导出市场调查数据,在 Excel 中进行详细的分析和可视化。
  5. 批量数据处理:当用户需要对大量数据进行批量处理时,导出为 Excel 文件可以方便地进行编辑和修改,然后再导入回系统。例如,人力资源部门可以导出员工信息进行批量更新后再导入系统。
  6. 合规与审计需求:某些行业和组织有合规和审计要求,需要定期导出数据以供审计和检查。例如,金融机构需要导出交易记录以满足监管要求。

二、现有解决方案与技术栈

  • 服务器端技术:如 Python 的 Pandas 库、Node.js 的 ExcelJS 库、Java 的 Apache POI 库等,用于生成 Excel 文件。
  • 前端技术:如 JavaScript 的 SheetJS 库,用于在浏览器中生成和下载 Excel 文件。
  • API 接口:通过 RESTful API 或 GraphQL 接口,从服务器获取数据并生成 Excel 文件。

Java 中,常见的 Excel 导出方案包括:

1、Apache POI:

优点:

  • 功能强大,支持读写 Microsoft Excel 97-2003 (XLS) 和 Excel 2007+ (XLSX) 文件。
  • 社区活跃,文档和示例丰富。
  • 支持复杂的 Excel 操作,如公式、图表、样式等。

缺点:

  • API 较为复杂,上手需要一定时间。
  • 性能在处理大文件时可能不够理想。

2、JExcelAPI (JXL)

优点:

  • 简单易用,适合处理基本的 Excel 操作。
  • 对 Excel 97-2003 (XLS) 文件有较好的支持。

缺点:

  • 不支持 Excel 2007+ (XLSX) 文件。
  • 功能相对有限,不支持复杂的操作如图表和公式。

3、EasyExcel

EasyExcel 因其高性能、简单易用、功能丰富以及良好的社区支持,成为了许多企业在实现 Excel 导出功能时的首选工具。

优点:

  • 由阿里巴巴开源,专注于高性能的 Excel 读写。
  • 支持 Excel 2007+ (XLSX) 文件。
  • API 简洁,易于使用,特别适合大数据量的导入导出。

缺点:

  • 相对于 Apache POI,功能较少,不支持一些复杂的操作。

4、OpenCSV (用于处理 CSV 文件)

优点:

  • 轻量级,简单易用。
  • 专注于 CSV 格式,性能好。

缺点:

  • 仅支持 CSV 文件,不支持 XLS 或 XLSX 格式。
  • 功能较为单一,只能处理简单的文本数据。

5、JasperReports

优点:

  • 强大的报表生成工具,支持多种格式(包括 Excel)。
  • 可以结合 iReport 等工具进行可视化设计。
  • 支持复杂的报表需求,如分组、汇总、图表等。

缺点:

  • 学习曲线较陡,需要掌握报表设计和配置。
  • 配置和使用较为复杂,适合有报表需求的场景。

6、Spire.XLS for Java

优点:

  • 商业库,提供全面的 Excel 操作功能。
  • 支持所有版本的 Excel 文件格式。
  • 易于使用,文档和技术支持完善。

缺点:

  • 商业软件,需要购买许可证。
  • 社区支持和开源资源较少。

7、Aspose.Cells for Java

优点:

  • 商业库,功能非常强大,支持所有 Excel 文件格式。
  • 提供丰富的 API,可以处理复杂的 Excel 操作,如公式、图表、数据透视表等。
  • 性能优秀,适合处理大数据量的 Excel 文件。

缺点:

  • 商业软件,价格较高。
  • 学习成本较高,需要深入了解其 API。

三、思考:基于 JNI + Rust 的导出方案

1、优势

将 Excel 文件的生成任务交给 Rust 来处理,可以充分利用 Rust 的高性能和内存安全特性,确保文件生成过程高效且可靠。同时,Java 负责 API 接口请求和业务逻辑处理,利用其成熟的生态系统和广泛的企业应用经验,使得整个系统更加易于维护和扩展。

2、职责

Rust 部分:

  • 使用 rust-xlsxwriter 等库来处理 Excel 文件的生成和导出。
  • 将生成的 Excel 文件保存到服务器的某个位置,或者直接返回给调用方。

Java 部分:

  • 使用 Spring Boot 或其他框架来创建 RESTful API。
  • 在接收到请求后,通过 JNI(Java Native Interface)或通过命令行调用 Rust 程序来生成 Excel 文件。
  • 将生成的文件返回给客户端,或者提供下载链接。

补充:rust_xlsxwriter 介绍

rust_xlsxwriter 是一个用于在 Rust 编程语言中创建和写入 Excel 文件(.xlsx 格式)的库。这个库提供了一种简单且高效的方法来生成 Excel 文件,适用于需要处理电子表格数据的各种应用场景,如数据分析、报告生成等。

主要特性

  1. 易于使用:rust_xlsxwriter 提供了直观的 API,使得创建和操作 Excel 文件变得非常简单。
  2. 支持多种数据类型:可以在单元格中写入字符串、数字、日期和布尔值等多种数据类型。
  3. 格式化功能:支持丰富的单元格格式化选项,包括字体样式、颜色、边框和对齐方式等。
  4. 工作表管理:可以创建多个工作表,并在不同的工作表之间切换和操作。
  5. 公式支持:允许在单元格中插入 Excel 公式,自动计算结果。
  6. 图表支持:能够在工作表中插入各种类型的图表,如柱状图、折线图和饼图等。
  7. 性能优化:针对大数据量的处理进行了优化,确保生成 Excel 文件的效率。

四、实践:检验真理的唯一标准

1、使用 Rust 导出 Excel

主要使用 rust_xlsxwriter 这个库,

https://docs.rs/rust_xlsxwriter/latest/rust_xlsxwriter/

示例

创建一个 Rust 项目,添加 rust_xlsxwriter 依赖,

# Cargo.toml
[dependencies]
rust_xlsxwriter = {
    version = "0.79.4" , features =["zlib","ryu","polars","serde","constant_memory"]  }

修改官网示例,这里尝试导出 10 万行数据,

// main.rs
fn main() -> Result<(), XlsxError> {
   
    // Create a new Excel file object.
    let mut workbook = Workbook::new();

    // Create some formats to use in the worksheet.
    let date_format = Format::new().set_num_format("yyyy-mm-dd");

    // Add a worksheet to the workbook.
    let worksheet = workbook.add_worksheet();

    // Set the column width for clarity.
    worksheet.set_column_width(0, 16)?;
    worksheet.set_column_width(5, 22)?;

    // Generate data in parallel.
    let data: Vec<Vec<CellValue>> = (0..ROWS)
        .into_par_iter()
        .map(|i| generate_row_data(i))
        .collect();

    // Write data to the worksheet in batches.
    for (i, row_data) in data.chunks(BATCH_SIZE).enumerate() {
   
        for (j, row) in row_data.iter().enumerate() {
   
            let row_index = i * BATCH_SIZE + j;
            for (col, value) in row.iter().enumerate() {
   
                match value {
   
                    CellValue::String(s) => worksheet.write(row_index as u32, col as u16, *s)?,
                    CellValue::Number(n) => worksheet.write(row_index as u32, col as u16, *n)?,
                    CellValue::Date(d) => worksheet.write_with_format(
                        row_index as u32,
                        col as u16,
                        d,
                        &date_format,
                    )?,
                    CellValue::Url(u) => {
   
                        worksheet.write(row_index as u32, col as u16, Url::new(*u))?
                    }
                };
            }
        }
    }

    // Save the file to disk.
    workbook.save("parallel_demo.xlsx")?;

    Ok(())
}

编译运行后报错 attempt to add with overflow

thread 'main' panicked at /home/sam/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/rust_xlsxwriter-0.79.4/src/relationship.rs:112:9:
attempt to add with overflow

原因分析:点击报错提示查看源码,发现 id_num定义的数据类型是 u16,在 Rust 中 u16 表示一个无符号 16 位整数类型,它的取值范围是从 0 到 65535(即 2^16 - 1),而我们导出的数据行数是 10 万,所以在加法运算的时候溢出了数值范围。


解决方案:使用 u32 类型,重新编译。

在这里插入图片描述

运行效果:可以看到 Excel 文件已经成功导出了,

在这里插入图片描述

10W数据量也可以正常导出,

在这里插入图片描述
在这里插入图片描述

2、导出 Rust 库文件

创建一个 Rust 库项目,

cargo new my_excel_writer_lib --lib
[dependencies]
jni = "0.21.1"
rust_xlsxwriter = {
    version = "0.79.4" , features =["zlib","ryu","polars","serde","constant_memory"]  }

[lib]
crate-type = ["cdylib"]

定义一个结构体,用于保存 Excel 指针,

#[repr(C)]
pub struct WorksheetHandle {
   
    workbook: *mut Workbook,
    worksheet: *mut Worksheet,
}

定义 createWorksheet 用于初始化创建 Excel 并返回指针,


#[no_mangle]
pub extern "system" fn Java_com_yushanma_crazyexcel_handler_MyExportResultHandler_createWorksheet(
    _env: JNIEnv,
    _class: JClass,
) -> jlong {
   
    let workbook = Box::new(Workbook::new(

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/927100.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用 Tkinter 创建一个简单的 GUI 应用程序来合并视频和音频文件

使用 Tkinter 创建一个简单的 GUI 应用程序来合并视频和音频文件 Python 是一门强大的编程语言&#xff0c;它不仅可以用于数据处理、自动化脚本&#xff0c;还可以用于创建图形用户界面 (GUI) 应用程序。在本教程中&#xff0c;我们将使用 Python 的标准库模块 tkinter 创建一…

「Mac畅玩鸿蒙与硬件35」UI互动应用篇12 - 简易日历

本篇将带你实现一个简易日历应用&#xff0c;显示当前月份的日期&#xff0c;并支持选择特定日期的功能。用户可以通过点击日期高亮选中&#xff0c;还可以切换上下月份&#xff0c;体验动态界面的交互效果。 关键词 UI互动应用简易日历动态界面状态管理用户交互 一、功能说明…

江协科技最新OLED保姆级移植hal库

江协科技最新OLED移植到hal库保姆级步骤 源码工程存档 工程和源码下载(密码 1i8y) 原因 江协科技的开源OLED封装的非常完美, 可以满足我们日常的大部分开发, 如果可以用在hal库 ,将是如虎添翼, 为我们开发调试又增加一个新的瑞士军刀, 所以我们接下来手把手的去官网移植源码…

NLTK工具包

NLTK工具包 NLTK工具包安装 非常实用的文本处理工具&#xff0c;主要用于英文数据&#xff0c;历史悠久~ 安装命令&#xff1a; pip install nltk import nltk # nltk.download() # nltk.download(punkt) # nltk.download(stopwords) # nltk.download(maxent_ne_chunker) nl…

HarmonyOS:使用Emitter进行线程间通信

Emitter主要提供线程间发送和处理事件的能力&#xff0c;包括对持续订阅事件或单次订阅事件的处理、取消订阅事件、发送事件到事件队列等。 一、Emitter的开发步骤如下&#xff1a; 订阅事件 import { emitter } from kit.BasicServicesKit; import { promptAction } from kit.…

Unity之一键创建自定义Package包

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity之一键创建自定义Package包 TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心进取&#xff01; …

【html网页页面007】html+css制作旅游主题内蒙古网页制作含注册表单(4页面附效果及源码)

旅游家乡主题网页制作 &#x1f964;1、写在前面&#x1f367;2、涉及知识&#x1f333;3、网页效果&#x1f308;4、网页源码4.1 html4.2 CSS4.3 源码获取 &#x1f40b;5、作者寄语 &#x1f964;1、写在前面 家乡网站主题内蒙古的网页 一共4个页面 网页使用htmlcss制作页面…

Ardupilot开源无人机之Geek SDK讨论

Ardupilot开源无人机之Geek SDK讨论 1. 源由2. 假设3. 思考3.1 结构构型3.2 有限资源3.3 软硬件构架 4.Ardupilot构架 - 2024kaga Update5. 讨论5.1 话题1&#xff1a;工作模式5.2 话题2&#xff1a;关键要点5.3 话题3&#xff1a;产品设计 6. Geek SDK - OpenFire6.1 开源技术…

JavaWeb——Maven高级

11.1. 分模块设计与开发 将项目按照功能拆分成若干个子模块&#xff0c;方便项目的管理维护、扩展&#xff0c;也方便模块之间的互相调用&#xff0c;资源共享。 11.2. 继承与聚合 11.2.1. 继承 父工程的的打包方式必须为pom 实现步骤 11.2.2. 版本锁定 dependencyManagemen…

Python中的实用工具JSON解析

对于Python不熟悉的同学&#xff0c;建议从本专栏第一篇开始观看 https://blog.csdn.net/qq_20330595/category_12844705.html 先上效果图 代码 import threading import tkinter as tk import json from tkinter import scrolledtext import tkinter.filedialog as filedialo…

医学临床机器学习中算法公平性与偏差控制简析

摘要 随着医疗领域中数据的不断积累和计算能力的提升&#xff0c;临床机器学习技术发展迅速&#xff0c;但算法不公平性和偏差问题凸显。本文深入探讨了临床机器学习算法公平性的重要性、概念与定义、在临床应用中的影响、偏差来源、降低偏差方法及提升公平性策略。通过对不同…

【数据结构】二叉搜索树(二叉排序树)

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;数据结构 目录 前言 一、什么是二叉搜索树 二、二叉搜索树的实现 节点 属性和接口的声明 插入 查找 删除 拷贝构造 析构 中序遍历 三、二叉搜索树的…

如何启用本机GPU硬件加速猿大师播放器网页同时播放多路RTSP H.265 1080P高清摄像头RTSP视频流?

目前市面上主流播放RTSP视频流的方式是用服务器转码方案&#xff0c;这种方案的好处是兼容性更强&#xff0c;可以用于不同的平台&#xff0c;比如&#xff1a;Windows、Linux或者手机端&#xff0c;但是缺点也很明显&#xff1a;延迟高、播放高清或者同时播放多路视频视频容易…

乘积求导法则、除法求导法则和链式求导法则

乘积求导法则、除法求导法则和链式求导法则 1. Constant multiples of functions (函数的常数倍)2. Sums and differences of functions (函数和与函数差)3. Products of functions via the product rule (通过乘积法则求积函数的导数)4. Quotients of functions via the quoti…

2个GitHub上最近比较火的Java开源项目

1. SpringBlade 微服务架构 标题 SpringBlade 微服务架构 摘要 SpringBlade 是一个由商业级项目升级优化而来的微服务架构&#xff0c;采用Spring Boot 3.2、Spring Cloud 2023等核心技术构建&#xff0c;遵循阿里巴巴编码规范&#xff0c;提供基于React和Vue的两个前端框架&am…

Ubuntu 安装 MariaDB

安装 MariaDB具体步骤 1、更新软件包索引&#xff1a; sudo apt update2、安装 MariaDB 服务器&#xff1a; sudo apt install mariadb-server3、启动 MariaDB 服务&#xff08;如果未自动启动&#xff09;&#xff1a; sudo systemctl start mariadb4、设置 MariaDB 开机启…

一体化数据安全平台uDSP 入选【年度创新安全产品 TOP10】榜单

近日&#xff0c;由 FreeBuf 主办的 FCIS 2024 网络安全创新大会在上海隆重举行。大会现场揭晓了第十届 WitAwards 中国网络安全行业年度评选获奖名单&#xff0c;该评选自 2015 年举办以来一直饱受赞誉&#xff0c;备受关注&#xff0c;评选旨在以最专业的角度和最公正的态度&…

相同的二叉树

给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 示例 1&#xff1a; 输入&#xff1a;p [1,2,3], q [1,2,3] 输出&#xff1a;true示例 2&…

百度地图JSAPI WebGL v1.0类参考

百度地图JSAPI WebGL v1.0类参考 核心类 Map 此类是地图API的核心类&#xff0c;用来实例化一个地图。请注意WebGL版本的地图API的命名空间是BMapGL。 示例&#xff1a;const map new BMapGL.Map(container); 构造函数描述Map(container: String | HTMLElement, opts: Map…

【k8s】监控metrics-server

metrics-server介绍 Metrics Server是一个集群范围的资源使用情况的数据聚合器。作为一个应用部署在集群中。Metric server从每个节点上KubeletAPI收集指标&#xff0c;通过Kubernetes聚合器注册在Master APIServer中。为集群提供Node、Pods资源利用率指标。 就像Linux 系统一样…