Excel文件解析---超大Excel文件读写

1.使用POI写入
当我们想在Excel文件中写入100w条数据时,使用XSSFWorkbook进行写入时会发现,只有将100w条数据全部加载到内存后才会用write()方法统一写入,效率很低,所以我们引入了SXXFWorkbook进行超大Excel文件读写。

通过设置 SXXFWorkbook 的构造参数,可以设置每次在内存中保持的行数,当达到这个值的时候,那么会把这些数据flush 到磁盘上,这样就不会出现内存不够的情况。

package com.ztt.Demo02;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.UUID;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

public class demo07 {
	public static void main(String[] args) {
		try (SXSSFWorkbook workbook = new SXSSFWorkbook(100);
				FileOutputStream fos = new FileOutputStream("D:\\test\\tt\\temp.xlsx")){
				Sheet sheet1 = workbook.createSheet();
				
				for (int i = 0; i <= 1000000; i++) {
					Row row = sheet1.createRow(i);
					Cell cell0 = row.createCell(0);
					cell0.setCellValue(UUID.randomUUID().toString());
					Cell cell1 = row.createCell(1);
					cell1.setCellValue( new Date());
				}
				
				workbook.write(fos );
			}catch (IOException e) {
					e.printStackTrace();
			}
	}
}

2.使用EasyExcel写入

        使用EasyExcel,我们首先要导入相关jar包

准备一个普通的Order类:

public class Order {
    private String orderId;
 
	private Double payment;
 
    public Order() {
		this.orderId=LocalDateTime.now().
           format(DateTimeFormatter.ofPattern(
           "yyyyMMddHHmmss"))+UUID.randomUUID()
           .toString().substring(0,5);
		this.payment=Math.random()*1000;
 
	}
 
	public String getOrderId() {
		return orderId;
	}
 
	public void setOrderId(String orderId) {
		this.orderId = orderId;
	}
 
	public Double getPayment() {
		return payment;
	}
 
	public void setPayment(Double payment) {
		this.payment = payment;
	}
	@Override
	public String toString() {
		return "Order [orderId=" + orderId + ", payment=" 
                                                + payment + "]";
	}
}

  我们发现,Order类中的成员变量名就是我们生成的Excel文件中的列头。那么如果我们想自定义列头时,我们可以用:@ExcelProperty("列头名") 

然后我们来通过EasyExcel来将100w条数据写入excel文件:

package com.ztt.demo01;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;

public class Test1 {
	public static void main(String[] args) {
		//将100w条订单数据写入Excel文件
//		EasyExcel.write("D:\\test\\poi\\alibaba\\0421-a.xlsx",Order.class)
//		.sheet("订单数据")
//		.doWrite(createOrderData());
		
		//读取Excel文件中的数据
		//参数1:文件的的路径
		//参数2:文件中每条数据对应的Class类型
		//参数3:如何解析
		EasyExcel.read("D:\\test\\poi\\alibaba\\0421-a.xlsx",Order.class,new AnalysisEventListener<Order>() {
			
			//读取列头
			@Override
			public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
				System.out.println("Excel文件的列头:"+headMap);
			}
			
			//处理每行数据
			@Override
			public void invoke(Order order, AnalysisContext arg1) {
				System.out.println("读取到一条订单数据:"+order);
			}
			
			@Override
			public void doAfterAllAnalysed(AnalysisContext arg0) {
				System.out.println("读取完毕");
				
			}
		}).sheet().doRead();
	}
	
	//生成100w条订单数据
	private static List<Order> createOrderData() {
		List<Order> orderList=new ArrayList<Order>();
		for(int i=0;i<1000;i++) {
			orderList.add(new Order());
		}
		return orderList;
	}
}

当我们想加入一列日期数据时:

public class Order {
    @ExcelProperty("订单编号")
	private String orderId;
	
	@ExcelProperty("支付金额")
	private Double payment;
 
	@ExcelProperty("创建时间")
	private LocalDateTime  creatTime;
    public Order() {
		this.orderId=LocalDateTime.now().
           format(DateTimeFormatter.ofPattern(
           "yyyyMMddHHmmss"))+UUID.randomUUID()
           .toString().substring(0,5);
		this.payment=Math.random()*1000;
		this.creatTime=LocalDateTime.now();
	}
 
	public String getOrderId() {
		return orderId;
	}
 
	public void setOrderId(String orderId) {
		this.orderId = orderId;
	}
 
	public Double getPayment() {
		return payment;
	}
 
	public void setPayment(Double payment) {
		this.payment = payment;
	}
    
    public LocalDateTime getCreatTime() {
		return creatTime;
	}
 
	public void setCreatTime(LocalDateTime creatTime) {
		this.creatTime = creatTime;
	}
	@Override
	public String toString() {
		return "Order [orderId=" + orderId + ", payment=" + payment
                                 + ", creatTime=" + creatTime + "]";
	}
}

运行结果: 

通过阅读报错提示(Can not find 'Converter' support class LocalDateTime.) ,我们大概可以知道,是因为找不到一个支持LocalDateTime类的转换器,所以为了解决这个问题,我们可以自己写一个比较器类:

package com.ztt.demo01;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;

public class LocalDateTimeConverter implements Converter<LocalDateTime>{
	
	//Excel文件中的类型
	@Override
	public CellDataTypeEnum supportExcelTypeKey() {
		return CellDataTypeEnum.STRING;
	}
	
	//程序中的类型
	@Override
	public Class supportJavaTypeKey() {
		return LocalDateTime.class;
	}
	
	//将LocalDateTime类型的数据转换成String类型的数据
	//并封装至一个Excel文件中的ellData
	@Override
	public CellData convertToExcelData(LocalDateTime value, ExcelContentProperty arg1, GlobalConfiguration arg2)
			throws Exception {
		return new CellData<>(
				value.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss")));
	}
	
	//从ce1lData中获取一个String类型的致据
	//并转换成LocalDateTime类型
	@Override
	public LocalDateTime convertToJavaData(CellData cellData ,ExcelContentProperty arg1, GlobalConfiguration arg2)
			throws Exception {
		return LocalDateTime.parse(cellData.getStringValue(),DateTimeFormatter.ofPattern( "yyyy年MM月dd日 HH:mm:ss"));
	}

	

}

当我们写好这个比较器后,就需要给成员变量creatTime显示的设置好比较器:

package com.ztt.demo01;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.NumberFormat;

public class Order {
		@ExcelProperty("订单编号")
		private String orderId;//订单编号
		
		@ExcelProperty("支付金额")
		@NumberFormat("¥#,###")
		private Double payment;//支付金额

		//设置LocalDateTime对应转换器
		@ExcelProperty(value="创建时间",converter=LocalDateTimeConverter.class)
		private LocalDateTime createionTime;//创建日期
		
		
		public Order() {
			this.orderId=LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHss"))+UUID.randomUUID().toString().substring(0,5);
			this.payment=Math.random()*10000;
			this.createionTime=LocalDateTime.now();
		}

		public String getOrderId() {
			return orderId;
		}

		public void setOrderId(String orderId) {
			this.orderId = orderId;
		}

		public Double getPayment() {
			return payment;
		}

		public void setPayment(Double payment) {
			this.payment = payment;
		}

		public LocalDateTime getCreateionTime() {
			return createionTime;
		}

		public void setCreateionTime(LocalDateTime createionTime) {
			this.createionTime = createionTime;
		}

		@Override
		public String toString() {
			return "Order [orderId=" + orderId + ", payment=" + payment + ", createionTime=" + createionTime + "]";
		}
		


}

运行结果:

练习:检查Excel文件 

1.序号是否连续

2.检查性别是否为男或女

3.身份证号

        3.1 身份证号码格式(必须为18位)

        3.2 身份证号码不能重复

        3.3 身份证号码开头两位是否与籍贯符合

                北京 11 天津12 河北 13 山西14 内蒙古 15

                陕西61 甘肃62 青海 63

4.学历只能填写:大专、本科、硕士、其它

5.体重在40-120之间

package com.ztt.Demo02;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class demo05 {
	public static void main(String[] args) {

		List<String> errorMsgList = validateDataExcel("D:\\test\\tt\\demo-data.xlsx");

		if (errorMsgList.size() == 0) {
			System.out.println("文件检查无误!");
		} else {
			// 显示所有错误信息
			for (String err : errorMsgList) {
				System.out.println(err);
			}
		}

	}

	public static List<String> validateDataExcel(String excelDataFilePath) {
		
		// 1.序号是否连续
		// 2.检查性别是否为男或女
		// 3.身份证号
		// 3.1 身份证号码格式(必须为18位)
		// 3.2 身份证号码不能重复
		// 3.3 身份证号码开头两位是否与籍贯符合
		// 北京 11 天津12 河北 13 山西14 内蒙古 15
		// 陕西61 甘肃62 青海 63
		// 4.学历只能填写:大专、本科、硕士、其它
		// 5.体重在40-120之间
		
		//创建用于保存错误提示信息的集合
		ArrayList<String> errorList=new ArrayList<String>();
		
		//创建用于检查身份证号码是否重复的set集合
		HashSet<String> idCardNoSet = new HashSet<String>();

		//创建用于检查身份证号码前2位与籍贯省份之间的映射关系的Map集合
		//北京11天津12河北13山西14内蒙古15
		//陕西61甘肃62青海63
		HashMap<String,String> provinceMap = new HashMap<String,String>() {
		//构造代码块
		{
			put("11","北京");
			put("12","天津");
			put( "13","河北");
			put("14","山西");
			put("15","内蒙古");
			put("61","陕西");
			put("62","甘肃");
			put("63","青海");
		}
	};
		//创建一个用于检查学历的List集合
		List<String> eduList = Arrays.asList("大专", "本科" , "硕士","其它");

	       
		
		try(Workbook workbook=new XSSFWorkbook(excelDataFilePath)){
			Sheet sheet=workbook.getSheetAt(0);
			
			for(int i=1;i<sheet.getLastRowNum();i++) {
				Row row =sheet.getRow(i);
				
				//1.序号是否连续
				Cell cellId=row.getCell(0);
				int rowNum=row.getRowNum();
				int id=(int)cellId.getNumericCellValue();
				if(rowNum!=id) {
					errorList.add(String.format("%d行的编号不连续!", rowNum));
				}
				
				//2.检查性别是否为男或女
				String gender=row.getCell(2).getStringCellValue();
				if(!gender.equals("男") && !gender.equals("女")) {
					errorList.add(String.format("%d行的性别有误!", rowNum));
				}

				//3.身份证号
				String idCardNo = row.getCell(3).getStringCellValue();
				
				//3.1身份证号码格式(必须为18位)
				if(idCardNo.length() != 18) {
					errorList.add(String.format("%d行的身份证号码长度有误! ",rowNum));
				}
				
				//3.2身份证号码不能重复
				if(!idCardNoSet.add(idCardNo)) {
					errorList.add(String.format("%d行的身份证号码重复存在! ",rowNum));
				}
				
				//3.3身份证号码开头两位是否与籍贯符合
				//北京11天津12河北13山西14内蒙古15
				//陕西61甘肃62青海63
				String idCardNoHomeCode = idCardNo.substring(0,2);
				String homeValue = provinceMap.get(idCardNoHomeCode); //根据身份证号码前两位获取正确的籍贯省份名称
				String home = row.getCell(6).getStringCellValue();//获取表格中当前行的籍贯信息
				if(!homeValue.equals( home)) { 
					errorList.add(String.format("%d行的身份证籍贯信息不一致! ",rowNum));
			}


				//4.学历只能填写:大专、本科、硕士、其它
				String eduValue=row.getCell(7).getStringCellValue();
				if(!eduList.contains(eduValue)) {
					errorList.add(String.format("%d行的学历信息不符合规范! ",rowNum));
				}
			}

                
            
		
			
		} catch (IOException e) {
			e.printStackTrace();
		}

		return errorList;
	}

}

运行结果:

1行的学历信息不符合规范! 
3行的身份证籍贯信息不一致! 
4行的编号不连续!
5行的学历信息不符合规范! 
7行的身份证号码长度有误! 
9行的身份证号码长度有误! 
9行的学历信息不符合规范! 
10行的身份证籍贯信息不一致! 
11行的身份证号码长度有误! 
12行的编号不连续!
13行的身份证号码长度有误! 
14行的学历信息不符合规范! 
15行的学历信息不符合规范! 
16行的性别有误!
18行的编号不连续!
22行的身份证籍贯信息不一致! 
24行的身份证号码重复存在! 
25行的性别有误!
33行的身份证号码重复存在! 
36行的身份证号码长度有误! 
39行的身份证籍贯信息不一致! 
41行的身份证籍贯信息不一致! 
43行的身份证籍贯信息不一致! 
44行的身份证籍贯信息不一致! 
46行的身份证籍贯信息不一致! 


 

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

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

相关文章

图像降噪算法 BM3D 介绍

介绍 BM3D 是 “Block-Matching and 3D Filtering” 的缩写&#xff0c;即三维块匹配滤波&#xff0c;它是一种用于图像去噪的算法。该算法来源于 一篇“Image and video denoising by sparse 3D transform-domain collaborative filtering”的高质量文章&#xff0c;文章的作…

软件测试面试问题汇总

一般软件测试的面试分为三轮&#xff1a;笔试&#xff0c;HR面试&#xff0c;技术面试。 前两轮&#xff0c;根据不同企业&#xff0c;或有或无&#xff0c;但最后一个技术面试是企业了解你“行不行”的关键环节&#xff0c;每个企业都会有的。 在平时的学习、工作中一定要善于…

为什么要学Python?学Python有什么用?

为什么要学Python&#xff1f;学Python有什么用&#xff1f; 在当今的数字化时代&#xff0c;编程已成为一项宝贵的技能。Python&#xff0c;作为一种流行的编程语言&#xff0c;因其易于学习和强大的功能而受到全球开发者的青睐。本文将探讨学习Python的原因和它的实际应用&am…

MLP实现fashion_mnist数据集分类(1)-模型构建、训练、保存与加载(tensorflow)

1、查看tensorflow版本 import tensorflow as tfprint(Tensorflow Version:{}.format(tf.__version__)) print(tf.config.list_physical_devices())2、fashion_mnist数据集下载与展示 (train_image,train_label),(test_image,test_label) tf.keras.datasets.fashion_mnist.l…

如何使git提交的时候忽略一些特殊文件?

认识.gitignore文件 在生成远程仓库的时候我们会看到这样一个选项&#xff1a; 这个.gitignore文件有啥用呢&#xff1f; .gotignore文件是Git版本控制系统中的一个特殊文件。用来指定哪些文件或者目录不被Git追踪或者提交到版本库中。也就意味着&#xff0c;如果我们有一些文…

怎么通过Java语言实现远程控制无人售货柜

怎么通过Java语言实现远程控制无人售货柜呢&#xff1f; 本文描述了使用Java语言调用HTTP接口&#xff0c;实现控制无人售货柜&#xff0c;独立控制售货柜、格子柜的柜门。 可选用产品&#xff1a;可根据实际场景需求&#xff0c;选择对应的规格 序号设备名称厂商1智能WiFi控…

使用 Postman 实现 API 自动化测试

背景介绍 相信大部分开发人员和测试人员对 postman 都十分熟悉&#xff0c;对于开发人员和测试人员而言&#xff0c;使用 postman 来编写和保存测试用例会是一种比较方便和熟悉的方式。但 postman 本身是一个图形化软件&#xff0c;相对较难或较麻烦&#xff08;如使用 RPA&am…

低功耗UPF设计的经典案列分享

案例1 分享个例子&#xff0c;景芯A72低功耗设计&#xff0c;DBG domain的isolation为何用VDDS_maia_noncpu供电而不是TOP的VDD&#xff1f; 答&#xff1a;因为dbg的上一级是noncpu&#xff0c;noncpu下面分成dbg和两个tbnk。 案例2 景芯A72的低功耗&#xff0c;请问&#…

精品干货 | 数据中台与数据仓库建设(免费下载)

【1】关注本公众号&#xff0c;转发当前文章到微信朋友圈 【2】私信发送 数据中台与数据仓库建设 【3】获取本方案PDF下载链接&#xff0c;直接下载即可。 如需下载本方案PPT/WORD原格式&#xff0c;请加入微信扫描以下方案驿站知识星球&#xff0c;获取上万份PPT/WORD解决方…

零基础入门学习Python第二阶01生成式(推导式),数据结构

Python语言进阶 重要知识点 生成式&#xff08;推导式&#xff09;的用法 prices {AAPL: 191.88,GOOG: 1186.96,IBM: 149.24,ORCL: 48.44,ACN: 166.89,FB: 208.09,SYMC: 21.29}# 用股票价格大于100元的股票构造一个新的字典prices2 {key: value for key, value in prices.i…

小微公司可用的开源ERP系统

项目介绍 华夏ERP是基于SpringBoot框架和SaaS模式的企业资源规划&#xff08;ERP&#xff09;软件&#xff0c;旨在为中小企业提供开源且易用的ERP解决方案。它专注于提供进销存、财务和生产功能&#xff0c;涵盖了零售管理、采购管理、销售管理、仓库管理、财务管理、报表查询…

Unreal Engine插件打包技巧

打开UE工程&#xff0c;点击编辑&#xff0c;选择插件&#xff0c;点击"打包"按钮&#xff0c;选择输出目录UE4.26版本打包提示需要VS2017问题解决 1&#xff09;用记事本打开文件【UE4对应版本安装目录\Epic Games\UE_4.26\Engine\Build\BatchFiles\RunUAT.bat】 2&…

单元测试配置

检查 vendor 目录下 是否有bin目录, bin目录下是否有 phpunit 文件 没有安装 composer require —dev phpunit/phpunit 确认版本是 PHPUnit 9.6.7配置IDE配置php解释器点击绿色箭头,运行测试查看效果备注: 单步调试需要安装 xdebug

5月6号作业

申请该结构体数组&#xff0c;容量为5&#xff0c;初始化5个学生的信息 使用fprintf将数组中的5个学生信息&#xff0c;保存到文件中去 下一次程序运行的时候&#xff0c;使用fscanf&#xff0c;将文件中的5个学生信息&#xff0c;写入(加载)到数组中去&#xff0c;并直接输出学…

Mysql索引失效情况

索引失效的情况 这是正常查询情况&#xff0c;满足最左前缀&#xff0c;先查有先度高的索引。 1. 注意这里最后一种情况&#xff0c;这里和上面只查询 name 小米科技 的命中情况一样。说明索引部分丢失&#xff01; 2. 这里第二条sql中的&#xff0c;status > 1 就是范围查…

性能超越!新模型Dragoman打造高质量英译乌翻译系统,打败现有SOTA模型

DeepVisionary 每日深度学习前沿科技推送&顶会论文分享&#xff0c;与你一起了解前沿深度学习信息&#xff01; 引言&#xff1a;探索乌克兰语的机器翻译挑战 在当今全球化迅速发展的背景下&#xff0c;机器翻译技术已成为沟通世界各地文化和语言的重要桥梁。尽管如此&…

【Axure高保真原型】动态伸缩信息架构图

今天和大家分享动态伸缩信息架构图的原型模板&#xff0c;我们可以通过点击加减按钮来展开或收起子内容&#xff0c;具体效果可以点击下方视频观看或者打开预览地址来体验 【原型效果】 【Axure高保真原型】动态伸缩信息架构图 【原型预览含下载地址】 https://axhub.im/ax9/…

Python从0到100(二十):文件读写和文件操作

一、文件的打开和关闭 有了文件系统可以非常方便的通过文件来读写数据&#xff1b;在Python中要实现文件操作是非常简单的。我们可以使用Python内置的open函数来打开文件&#xff0c;在使用open函数时&#xff0c;我们可以通过函数的参数指定文件名、操作模式和字符编码等信息…

关于蓝队应急响应工具箱意见征集

前言 征集一下各位师傅的意见&#xff0c;没用过的师傅可以去以往的文章下载使用&#xff1a; 下载地址&#xff08;有个小小改动&#xff0c;去除了必要的python环境&#xff0c;使其占用空间更小&#xff09;&#xff1a; [护网必备]知攻善防实验室蓝队应急响应工具箱v202…

自动化运维工具---Ansible

一 Puppet Puppet是历史悠久的运维工具之一。它是一种基础架构即代码(laC)工具&#xff0c;使用户可以定义其基础 架构所需的状态&#xff0c;并使系统自动化以实现相同状态。 Puppet可监视用户的所有系统&#xff0c;并防止任何偏离已定义状态的情况。从简单的工作流程自动…