当前位置: 首页 > news >正文

大批量数据导出csv,平替导出excel性能优化解决方案封装工具类

阿丹:

        有些业务逻辑需要在导出非常大量的数据,几百甚至几千万的数据这个时候再导出excel来对于性能都不是很友好,这个时候就需要替换实现思路来解决这个问题。

        本文章提供了两种解决的方案,也是两种从数据库中拿取数据的方式一种是原生的jdbc一种是使用mybatis来封装对象来完成的。

使用字符串数组的导出:

package com.lianlu.export.util;import org.apache.poi.ss.formula.functions.T;import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;/*** CSV导出工具类,用于将数据列表导出为CSV文件。*/
public class CSVExportUtil {/*** 导出CSV文件。** @param dataList          需要导出的内容,类型为字符串数组的列表。* @param validationRulesMap 校验和替换规则的映射,键为列索引,值为一个映射,其中键为需要替换的字符串,值为替换后的字符串。* @param headers           CSV文件的表头,类型为字符串数组。* @param fileName          导出CSV文件的名称。* @throws IOException 如果在写入文件过程中发生异常。*/public static void exportCSV(List<String[]> dataList, Map<Integer, Map<String, String>> validationRulesMap, String[] headers, String fileName) throws IOException {// 预处理数据(校验和替换)List<String[]> preprocessedDataList = preprocessData(dataList, validationRulesMap);// 写入CSV文件writeCSVToFile(preprocessedDataList, headers, fileName);}/*** 不需要替换规则的导出* @param dataList* @param headers* @param fileName* @throws IOException*/public static void exportCSV(List<String[]> dataList, String[] headers, String fileName) throws IOException {// 写入CSV文件writeCSVToFile(dataList, headers, fileName);}/*** 预处理数据列表(校验和替换)。** @param dataList          原始数据列表。* @param validationRulesMap 校验和替换规则的映射。* @return 预处理后的数据列表。*/private static List<String[]> preprocessData(List<String[]> dataList, Map<Integer, Map<String, String>> validationRulesMap) {return dataList.stream().map(row -> preprocessDataRow(row, validationRulesMap)).collect(Collectors.toList());}/*** 预处理单行数据(校验和替换)。** @param row               单行数据。* @param validationRulesMap 校验和替换规则的映射。* @return 预处理后的单行数据。*/private static String[] preprocessDataRow(String[] row, Map<Integer, Map<String, String>> validationRulesMap) {for (Map.Entry<Integer, Map<String, String>> entry : validationRulesMap.entrySet()) {int columnIndex = entry.getKey();Map<String, String> rules = entry.getValue();String originalValue = row[columnIndex];String replacedValue = rules.getOrDefault(originalValue, originalValue);row[columnIndex] = replacedValue;}return row;}/*** 将预处理后的数据写入CSV文件。** @param dataList   预处理后的数据列表。* @param headers    CSV文件的表头。* @param fileName   导出CSV文件的名称。* @throws IOException 如果在写入文件过程中发生异常。*/private static void writeCSVToFile(List<String[]> dataList, String[] headers, String fileName) throws IOException {try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {// 写入表头writer.write(String.join(",", headers));writer.newLine();// 分批写入数据以提高性能AtomicInteger counter = new AtomicInteger(0);while (counter.get() < dataList.size()) {int batchSize = Math.min(10000, dataList.size() - counter.get()); // 每次写入10000条数据,可根据实际需求调整List<String[]> batchData = dataList.subList(counter.get(), counter.get() + batchSize);for (String[] dataRow : batchData) {writer.write(String.join(",", dataRow));writer.newLine();}counter.addAndGet(batchSize);}}}/*** 从泛型对象中获取属性值并转换为字符串数组。** @param data 泛型对象* @return 字符串数组,包含对象的属性值*/private String[] convertObjectToArray(T data) {Class<?> clazz = data.getClass();Field[] fields = clazz.getDeclaredFields();// 获取对象的所有字段,并设置它们为可访问for (Field field : fields) {field.setAccessible(true);}String[] rowData = new String[fields.length];// 遍历所有字段,获取每个字段的值并添加到字符串数组中for (int i = 0; i < fields.length; i++) {try {rowData[i] = fields[i].get(data).toString();} catch (IllegalAccessException e) {throw new RuntimeException("Failed to access field value", e);}}return rowData;}}

通过对象的导出:

package com.lianlu.export.util;import java.io.*;
import java.lang.reflect.Field;
import java.util.*;public class CSVExportUtil<T> {/*** 导出CSV文件。** @param dataList       需要导出的数据列表(泛型对象列表)* @param validationRulesMap 校验和替换规则映射(键为列索引,值为校验和替换规则的映射)* @param headers         CSV表头数组* @param fileName        导出CSV文件的名称* @throws IOException 如果在写入文件时发生错误*/public void exportCSV(List<T> dataList, Map<Integer, Map<String, String>> validationRulesMap, String[] headers, String fileName) throws IOException {// 预处理数据(校验和替换)List<String[]> preprocessedData = preprocessData(dataList, validationRulesMap);// 写入CSV文件writeCSV(preprocessedData, headers, fileName);}/*** 预处理数据(校验和替换)。** @param dataList       数据列表(泛型对象列表)* @param validationRulesMap 校验和替换规则映射(键为列索引,值为校验和替换规则的映射)* @return 预处理后的数据(字符串数组列表)*/private List<String[]> preprocessData(List<T> dataList, Map<Integer, Map<String, String>> validationRulesMap) {List<String[]> preprocessedData = new ArrayList<>(dataList.size());for (T data : dataList) {String[] rowData = convertObjectToArray(data);preprocessedData.add(validateAndReplace(rowData, validationRulesMap));}return preprocessedData;}/*** 从泛型对象中获取属性值并转换为字符串数组。** @param data 泛型对象* @return 字符串数组,包含对象的属性值*/private String[] convertObjectToArray(T data) {Class<?> clazz = data.getClass();Field[] fields = clazz.getDeclaredFields();// 获取对象的所有字段,并设置它们为可访问for (Field field : fields) {field.setAccessible(true);}String[] rowData = new String[fields.length];// 遍历所有字段,获取每个字段的值并添加到字符串数组中for (int i = 0; i < fields.length; i++) {try {rowData[i] = fields[i].get(data).toString();} catch (IllegalAccessException e) {throw new RuntimeException("Failed to access field value", e);}}return rowData;}/*** 根据提供的校验和替换规则对字符串数组进行校验和替换。** @param rowData   字符串数组* @param rulesMap 校验和替换规则映射(键为列索引,值为校验和替换规则的映射)* @return 校验和替换后的字符串数组*/private String[] validateAndReplace(String[] rowData, Map<Integer, Map<String, String>> rulesMap) {for (Map.Entry<Integer, Map<String, String>> entry : rulesMap.entrySet()) {int columnIndex = entry.getKey();Map<String, String> ruleMap = entry.getValue();String currentValue = rowData[columnIndex];if (ruleMap.containsKey(currentValue)) {rowData[columnIndex] = ruleMap.get(currentValue);}}return rowData;}/*** 将预处理后的数据写入CSV文件。** @param preprocessedData 预处理后的数据(字符串数组列表)* @param headers          CSV表头数组* @param fileName         导出CSV文件的名称* @throws IOException 如果在写入文件时发生错误*/private void writeCSV(List<String[]> preprocessedData, String[] headers, String fileName) throws IOException {try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {CSVWriter csvWriter = new CSVWriter(writer);// 写入表头csvWriter.writeNext(headers);// 写入数据csvWriter.writeAll(preprocessedData);csvWriter.close();}}
}

相关文章:

大批量数据导出csv,平替导出excel性能优化解决方案封装工具类

阿丹&#xff1a; 有些业务逻辑需要在导出非常大量的数据&#xff0c;几百甚至几千万的数据这个时候再导出excel来对于性能都不是很友好&#xff0c;这个时候就需要替换实现思路来解决这个问题。 本文章提供了两种解决的方案&#xff0c;也是两种从数据库中拿取数据的方式一种是…...

C++ Qt开发:Charts绘制各类图表详解

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍TreeWidget与QCharts的常用方法及灵活运用。 …...

【SassVue】仿网易云播放器动画

简介 仿网易云播放动画 效果图&#xff08;效果图&#xff09; 最终成品效果 动画组件 src/components/music/MusicPlayAnimate.vue <template><div class"music-play"><div></div><div></div><div></div></di…...

CentOS进入单用户模式

一、重启 二、出现内核选项 按“e” 三、编辑这一行 输入 rw init/sysroot/bin/sh 四、进入单用户模式 ctrlx 进入 五、切换目录 chroot /sysroot 六、然后你就操作你的系统了。 修改密码等等...

微信小程序~如何设置页面的背景色

微信小程序~如何设置页面的背景色 众所周知&#xff0c;微信小程序每个页面由.json&#xff0c;.scss&#xff0c;.ts&#xff0c;.wxml这四个文件组成。 有的小伙伴会发现&#xff0c;需要给页面加背景色的时候&#xff0c;只需在此页面的.scss文件中写个page{background-colo…...

图灵日记之java奇妙历险记--输入输出方法数组

目录 输入输出输出到控制台从键盘输入使用 Scanner 读取字符串/整数/浮点数使用 Scanner 循环读取 猜数字方法方法定义方法调用的执行过程实参和形参的关系(重要)方法重载 数组数组的创建数组的初始化动态初始化静态初始化 数组的使用元素访问遍历数组 数组是引用类型null数组应…...

CSS新手入门笔记整理:CSS3弹性盒模型

特点 子元素宽度之和小于父元素宽度&#xff0c;所有子元素最终的宽度就是原来定义的宽度。子元素宽度之和大于父元素宽度&#xff0c;子元素会按比例来划分宽度。在使用弹性盒子模型之前&#xff0c;必须为父元素定义“display:flex;”或“display:inline-flex;”。 弹性盒子…...

OCP NVME SSD规范解读-1

OCP&#xff08;Open Compute Project&#xff09;是一个由Facebook于2011年发起的开源项目。其目标是重新设计和优化数据中心的硬件&#xff0c;包括服务器、存储、网络设备等&#xff0c;以提高效率&#xff0c;降低运营成本&#xff0c;并推动技术的创新和标准化。 在OCP中&…...

大规模和复杂问题挑战——分治思想来应战

分治思想利用了问题的内在结构和性质&#xff0c;使得大规模和复杂的问题能够被有效地解决。具体来说&#xff0c;分治思想的本质是通过问题分解、递归处理和解的合并&#xff0c;将一个复杂问题转化为一系列更简单的子问题&#xff0c;并最终得到原问题的解。 1、分治思想的本…...

六西格玛的科技漩涡——张驰咨询如何促成企业变革

在管理的海洋里&#xff0c;六西格玛管理是一艘稳健的航船&#xff0c;在质量管理的汪洋中乘风破浪&#xff0c;尽管质疑之声像远处的风暴不断逼近&#xff0c;但张驰咨询公司依靠这艘航船坚持初心&#xff0c;驭风而行。 20载耕耘&#xff0c;张驰咨询不仅仅是培养了超过8000…...

由于被认为是客户端对错误(例如:畸形的请求语法、无效的请求信息帧或者虚拟的请求路由),服务器无法或不会处理当前请求。

问题描述&#xff1a; 由于被认为是客户端对错误&#xff08;例如&#xff1a;畸形的请求语法、无效的请求信息帧或者虚拟的请求路由&#xff09;&#xff0c;服务器无法或不会处理当前请求。 在实现向数据库中添加记录时&#xff0c;请求发送无效&#xff0c;参数也未传递到控…...

【案例】图片预览

效果图 如何让图片放大&#xff0c;大多数的UI组件都带有这种功能&#xff0c;今天给大家介绍的这个插件除了放大之外&#xff0c;还可以旋转、移动、翻转、旋转、二次放大&#xff08;全屏&#xff09; 实现 npm i v-viewer -Smain.js 中引入 import viewerjs/dist/viewer.c…...

ubuntu 18/20/22 安装 mysql 数据库

这里写自定义目录标题 ubuntu 18/20/22 安装 mysql 数据库1. 准备2. 安装 mysql3. 配置4. 测试 demo 用户5 服务管理5.1 查看服务状态5.2 启动服务5.3 停止服务5.4 重启服务 ubuntu 18/20/22 安装 mysql 数据库 1. 准备 安装前需要知道 root 用户的密码 假如不知道 root 用户…...

通过U盘:将电脑进行重装电脑

目录 一.老毛桃制作winPE镜像 1.制作准备 2.具体制作 下载老毛桃工具 插入U盘 选择制作模式 正式配置U盘 安装提醒 安装成功 具体操作 二.使用ultrasio制作U盘 1.具体思路 2.图片操作 三.硬盘安装系统 具体操作 示例图 ​编辑 一.老毛桃制作winPE镜像 1.制作准…...

C# SqlSugar 数据库 T4模板

生成效果 模板代码 <# template debug"false" hostspecific"true" language"C#" #> <# output extension".cs" #> <# assembly name"System.Core" #> <# assembly name"System.Data" #>…...

ARM AArch64的TrustZone架构详解(下)

目录 五、软件架构 5.1 顶层软件架构 5.2 信任消息(message) 5.3 调度 5.4 OPTEE...

《Nature》预测 2024 科技大事:GPT-5预计明年发布等

《Nature》杂志近日盘点了 2024 年值得关注的科学事件&#xff0c;包括 GPT-5 与新一代 AlphaFold、超算 Jupiter、探索月球任务、生产「超级蚊子」、朝向星辰大海、试验下一代新冠疫苗、照亮暗物质、意识之辩第二回合、应对气候变化。 今年以来&#xff0c;以 ChatGPT 为代表…...

「Verilog学习笔记」并串转换

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 串并转换操作是非常灵活的操作&#xff0c;核心思想就是移位。串转并就是把1位的输入放到N位reg的最低位&#xff0c;然后N位reg左移一位&#xff0c;在把1位输入放到左移后…...

应急响应常用命令

应急响应的基本思路 a. 收集信息&#xff1a;收集告警信息、客户反馈信息、设备主机信息等 b. 判断类型&#xff1a;安全事件类型判断。&#xff08;钓鱼邮件、Webshll、爆破、中毒等&#xff09; c. 控制范围&#xff1a;隔离失陷设备 d. 分析研判&#xff1a;根据收集回来的…...

使用React和ResizeObserver实现自适应ECharts图表

关键词 React ECharts ResizeObserver 摘要 在现代 Web 开发中&#xff0c;响应式布局和数据可视化是非常常见的需求。本文将介绍如何使用React、ResizeObserver和ECharts库来创建一个自适应的图表组件。 什么是ResizeObserver ResizeObserver是JavaScript的一个API&#x…...

解决企业级流程建模挑战:基于Vue与bpmn.js的Flowable工作流设计器深度集成指南

解决企业级流程建模挑战&#xff1a;基于Vue与bpmn.js的Flowable工作流设计器深度集成指南 【免费下载链接】workflow-bpmn-modeler &#x1f525; flowable workflow designer based on vue and bpmn.io7.0 项目地址: https://gitcode.com/gh_mirrors/wo/workflow-bpmn-mode…...

基于高斯过程回归的MATLAB时间序列区间预测代码实现与解析

基于高斯过程回归(GPR)的时间序列区间预测 GPR时间序列区间预测 matlab代码 暂无Matlab版本要求 -- 推荐 2018B 版本及以上做时间序列最烦的就是拍脑袋给个“明天涨3%左右”——“左右”到底是正负0.5还是正负3&#xff1f;如果是风电发电的负荷申报&#xff0c;正负差多了要罚…...

ostringstream清空缓存的正确姿势:str()与clear()的深度解析

1. 为什么ostringstream清空缓存这么让人困惑&#xff1f; 第一次用ostringstream的时候&#xff0c;我也被它坑过。记得当时写了个日志记录功能&#xff0c;反复往同一个ostringstream对象里写入内容&#xff0c;结果发现每次输出的日志都越积越长。我本能地调用了clear()&…...

告别盲打:用GDB和Python-pwntools动态调试分析jarvisoj_level2的栈溢出漏洞

逆向工程实战&#xff1a;用GDB与pwntools解剖jarvisoj_level2栈溢出漏洞 在二进制安全领域&#xff0c;栈溢出漏洞一直是攻防演练中的经典课题。今天我们将以jarvisoj_level2这道CTF题目为蓝本&#xff0c;深入探讨如何通过GDB动态调试与pwntools脚本的完美配合&#xff0c;实…...

Anthropic:AI 编程从单打独斗到团队协作的生产关系升级

【导语&#xff1a;在 AI 时代&#xff0c;编程不再是少数人的特权。Anthropic 让 Claude 独自完成项目&#xff0c;从单智能体到多智能体结构&#xff0c;实现了从生成代码到交付成果的跨越&#xff0c;带来了生产关系的升级。】Claude 单枪匹马难交付&#xff0c;多智能体团队…...

从vector的push_back看C++的‘完美转发’:一个emplace_back如何省掉一次临时对象构造

从vector的emplace_back揭秘C完美转发的魔法 在C的世界里&#xff0c;vector作为最常用的容器之一&#xff0c;其性能优化一直是开发者关注的焦点。当我们向vector添加元素时&#xff0c;push_back和emplace_back这两个看似相似的函数&#xff0c;背后却隐藏着现代C最精妙的语言…...

TransCAD新手必看:如何用表格链接快速创建矩阵OD并生成期望线(附详细步骤图)

TransCAD实战指南&#xff1a;从表格链接到期望线可视化的全流程解析 引言 在交通规划与空间分析领域&#xff0c;TransCAD作为一款专业的GIS软件&#xff0c;其强大的数据处理和可视化能力一直备受推崇。对于初学者而言&#xff0c;掌握表格链接创建矩阵OD并生成期望线的技巧&…...

基于AkShare构建A股基础数据自动化采集方案

1. 为什么需要自动化采集A股基础数据 做量化研究的朋友都知道&#xff0c;获取准确、完整的股票基础数据是策略开发的基石。我刚开始做量化时&#xff0c;最头疼的就是每次跑策略前都要手动更新股票列表&#xff0c;经常因为数据不全导致回测结果失真。后来发现AkShare这个宝藏…...

大厂笔试面试八股文-算法-数组常考题-final

刷了200道数组题,笔试面试还是不会做?这10道搞懂就够了 刷了200道数组题,面试还是不会做? 问题不是你刷得不够多,而是没抓住核心套路。 我整理了35道大厂真题,发现其实就5个核心技巧。今天把最重要的10道题和背后的套路,全部分享给你。 offer直通车-大厂校招大礼包&#x…...

Redis持久化:从AOF到RDB,如何实现数据不丢失?

Redis属于内存数据库&#xff0c;但为了防止宕机等导致的数据丢失&#xff0c;也有对应的数据持久化技术。持久化主要作用就是数据备份&#xff0c;即将数据存储在硬盘&#xff0c;保证数据不会因进程退出而丢失。 AOF持久化 Append Only File 类似于Mysql的binlog日志类似&…...