poi和easyExcel基于Java操作Excel学习笔记
1 學(xué)習(xí)前言
Excel和讀寫(xiě)和文件的讀寫(xiě)沒(méi)有本質(zhì)的區(qū)別,都是屬于IO操作,我們使用原生的IO就能解決Excel的導(dǎo)入和導(dǎo)出,當(dāng)然操作起來(lái)比較麻煩,性能也不高,這次我們就學(xué)習(xí)poi和easyExcel(它們都屬于第三方工具)的方式去基于Java和Mysql數(shù)據(jù)庫(kù)導(dǎo)入導(dǎo)出我們的Excel的數(shù)據(jù)
poi:Apache
easyExcel:阿里巴巴開(kāi)源的工具
2 使用常用場(chǎng)景
1 將大量的數(shù)據(jù)導(dǎo)入為excel表格
2 將excel表中的信息錄入到數(shù)據(jù)庫(kù)(比如習(xí)題上傳)(也叫批量插入),大大減輕我們?nèi)斯つ酥辆W(wǎng)站的錄入量
開(kāi)發(fā)中經(jīng)常會(huì)涉及到對(duì)Excel的處理,如導(dǎo)入Excel,導(dǎo)出Excel到數(shù)據(jù)庫(kù)
目前操作excel比較流行的就是Apache POI和阿里巴巴的easyExcel
3 Apache POI
官網(wǎng): https://poi.apache.org
Apache給我們提供的POI不僅可以操作excel格式,對(duì)于word,ppt,visio都是提供支持的,而且語(yǔ)法大概類(lèi)似
HSSF是處理普通的excel的
XSSF是處理OOXML格式的excel的
值得注意點(diǎn)是,雖然HSSF和XSSF都可以處理excel,但是還是有差距
比如excel主要有兩個(gè)版本 03版和07版,其中03版的行數(shù)最多只能存65535行,07版的是沒(méi)有限制的
如果想要操作Word,那么使用HWPF
如果想要操作PPT,那么使用HSLF
如果想要操作Visio,那么使用HDGF
原生的POI使用起來(lái)比較麻煩,而且量大的時(shí)候會(huì)報(bào)OOM異常(out of memory的簡(jiǎn)稱(chēng),稱(chēng)之為內(nèi)存溢出),但是現(xiàn)在很多市面上的工具底層也是會(huì)使用封裝POI的
4 easyExcel(阿里巴巴開(kāi)源工具)
官網(wǎng):https://github.com/alibaba/easyexcel
官方文檔:https://www.yuque.com/easyexcel/doc/easyexcel
easyExcel是阿里巴巴開(kāi)源的一個(gè)對(duì)于excel處理工具(框架)以使用簡(jiǎn)單,節(jié)省內(nèi)存著稱(chēng)
easyExcel能大大減少內(nèi)存占用的主要原因是在解析excel中沒(méi)有將文件數(shù)據(jù)一次性全部加載到內(nèi)存中,而是從磁盤(pán)上一行一行的讀取,逐個(gè)解析
由于POI比較原生比較復(fù)雜,我們后研發(fā)出新的(工具)框架easyExcel,它是阿里巴巴退出的對(duì)于POI的后續(xù)產(chǎn)品,并且對(duì)POI做了升級(jí)和優(yōu)化,不會(huì)因?yàn)閑xcel數(shù)據(jù)量過(guò)大引起oom異常(內(nèi)存溢出),使我們用起來(lái)更加的方便(讀寫(xiě)Excel只需要一行代碼!)
5 poi和easyExcel的不同
主要在于內(nèi)存和操作過(guò)程
比如我們現(xiàn)在excel表有100W數(shù)據(jù)
1 poi是先把數(shù)據(jù)加載到內(nèi)存,如果我們內(nèi)存比較小,Java是會(huì)直接報(bào)OOM內(nèi)存溢出異常,這時(shí)候就會(huì)有問(wèn)題,但是easyExcel它就比較簡(jiǎn)單只能,就算讀寫(xiě)100W行數(shù)據(jù),會(huì)一行一行的讀寫(xiě),不會(huì)直接全部解析
2poi會(huì)一次性全部讀取和返回execl表格的數(shù)據(jù),但是easyExcel不會(huì)這樣,它沒(méi)有將文件數(shù)據(jù)一次性全部加載到內(nèi)存中,而是從磁盤(pán)上一行一行的讀取,逐個(gè)解析
poi和easyExcel的本質(zhì)上就是時(shí)間和空間的轉(zhuǎn)換,根據(jù)我們的需求自行選擇即可
6 poi excel寫(xiě)
1 創(chuàng)建Java項(xiàng)目
2 pom引入依賴(lài)
<!--導(dǎo)入依賴(lài)jar包--> <!--xls(03)--> <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.9</version> </dependency><!--xlsx(07)--> <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.9</version> </dependency><!--日期格式化工具--> <dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId><version>2.10.1</version> </dependency><!--單元測(cè)試--> <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version> </dependency>3 本地創(chuàng)建兩個(gè)excel 分別是03版和07版
首先03版,它最多有65536行
但是07版的,是沒(méi)有限制的
他們對(duì)應(yīng)的后綴也是不一樣的,03版本的xls,07版本的是xslx,這意味著操作它們的工具類(lèi)也不相同.03版本用的是poi,07版用的則是poi-ooxml
4 Java的宗旨就是萬(wàn)物皆對(duì)象,我們也要把excel當(dāng)成我們的一個(gè)對(duì)象去處理
1 工作薄
首先我們打開(kāi)的excel就是一個(gè)大對(duì)象,也叫工作簿,它包括以下內(nèi)容
2 工作表
每一個(gè)sheet也是我們excel對(duì)象的屬性,也叫工作表,我們肯定是現(xiàn)有工作簿才會(huì)有工作表,而且會(huì)默認(rèn)自帶sheet,也可以根據(jù)我們的需要自行添加sheet工作表
3 行
excel中有很多行,每一行也是我們excel對(duì)象的屬性(橫的叫行,豎的叫列)
4 列
excel中有很多列,每一列也是我們excel對(duì)象的屬性(橫的叫行,豎的叫列)
5 單元格
一行一列有很多個(gè)單元格,每一個(gè)單元格也是我們excel對(duì)象的屬性
創(chuàng)建我們的測(cè)試類(lèi),創(chuàng)建Workbook對(duì)象,按著ctrl點(diǎn)進(jìn)去發(fā)現(xiàn)它是一個(gè)接口
點(diǎn)擊箭頭可以看到它的三個(gè)實(shí)現(xiàn)類(lèi)
定義工作簿,工作表,行列,單元格,和我們手動(dòng)創(chuàng)建excel是一樣的操作,只不過(guò)是用代碼來(lái)實(shí)現(xiàn)
03版本excel IO操作寫(xiě)的全部代碼如下
運(yùn)行后發(fā)現(xiàn),會(huì)在項(xiàng)目本地生成我們定義的excel,打開(kāi)查看
03版和07版的區(qū)別如下
1 03版本有最大長(zhǎng)度現(xiàn)在 07版本沒(méi)有
2 03版本后綴xls 07版本后綴xlsx
3 03版本使用的工具是HSSF,07版本使用的是XSSF
5 大數(shù)據(jù)繞導(dǎo)入導(dǎo)出(批量)
真實(shí)開(kāi)發(fā)中,大多數(shù)就是大數(shù)據(jù)批量導(dǎo)入或者導(dǎo)出excel
大文件寫(xiě)HSSF
缺點(diǎn):最多只能處理65536行,否則會(huì)報(bào)內(nèi)存溢出異常
優(yōu)點(diǎn):過(guò)程中寫(xiě)入緩存,不操作磁盤(pán),最后一次性寫(xiě)入磁盤(pán),速度快
大文件寫(xiě)XSSF
缺點(diǎn):寫(xiě)數(shù)據(jù)時(shí)速度非常慢,非常消耗內(nèi)存,也會(huì)發(fā)生內(nèi)存溢出,比如100萬(wàn)條
優(yōu)點(diǎn):可以寫(xiě)較大的數(shù)據(jù)量,比如20萬(wàn)條
03版本HSSF循環(huán)導(dǎo)入65536行數(shù)據(jù)(03版本最大行就是65536)
03版本HSSF循環(huán)插入65536條
package com.wyh.Test;import org.apache.poi.hssf.usermodel.HSSFWorkbook; 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.junit.Test;import java.io.FileOutputStream;/*** @program: JavaExecl* @description: 大數(shù)據(jù)量寫(xiě)03版本* @author: 魏一鶴* @createDate: 2021-12-14 23:31**/public class BigDateExcelWrite03 {//全局路徑,供我們操作使用方便static String path = "D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void BigDateExcelWrite03() throws Exception {//開(kāi)始時(shí)間 用于計(jì)算時(shí)間差long beginTime = System.currentTimeMillis();//創(chuàng)建工作簿 03版本使用HSSFWorkbook workbook = new HSSFWorkbook();//創(chuàng)建工作表 這里就不給它命令了 按照默認(rèn)的來(lái)Sheet sheet = workbook.createSheet();//寫(xiě)入數(shù)據(jù) 循環(huán)插入65536行數(shù)據(jù),03版的HSSF最多只能插入65536行for (int rowNum = 0; rowNum < 65536; rowNum++) {//循環(huán)創(chuàng)建行Row row = sheet.createRow(rowNum);for(int cellNum=0;cellNum<10;cellNum++){//循環(huán)插入列Cell cell = row.createCell(cellNum);//循環(huán)設(shè)置值cell.setCellValue(cellNum);}}System.out.println("生成excel表完畢");//03版本的后綴是xls//開(kāi)啟文件流FileOutputStream fileOutputStream = new FileOutputStream(path + "BigDateExcelWrite03.xlsx");//開(kāi)始寫(xiě)excelworkbook.write(fileOutputStream);//關(guān)閉流fileOutputStream.close();//結(jié)束時(shí)間long endTime = System.currentTimeMillis();//輸出花費(fèi)的時(shí)間System.out.println("花費(fèi)的時(shí)間:"+(double)(endTime - beginTime)/1000);} }運(yùn)行發(fā)現(xiàn)excel已經(jīng)創(chuàng)建成功,速度也非常的快
打開(kāi)查看
已知03版本xls最多存65536行,那么如果我們循環(huán)插入65537行會(huì)怎么樣呢? 保留源代碼,循環(huán)最大值設(shè)置為65537
再次運(yùn)行發(fā)現(xiàn)會(huì)報(bào)錯(cuò)
java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535)07版本XSSF循環(huán)插入65536條
把后綴改為xlsx,把HSSF緩存XSSF即可
package com.wyh.Test;import org.apache.poi.hssf.usermodel.HSSFWorkbook; 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; import org.junit.Test;import java.io.FileOutputStream;/*** @program: JavaExecl* @description: 大數(shù)據(jù)量寫(xiě)03版本* @author: 魏一鶴* @createDate: 2021-12-14 23:31**/public class BigDateExcelWrite07 {//全局路徑,供我們操作使用方便static String path = "D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void BigDateExcelWrite07() throws Exception {//開(kāi)始時(shí)間 用于計(jì)算時(shí)間差long beginTime = System.currentTimeMillis();//創(chuàng)建工作簿 07版本的使用XSSFWorkbook workbook = new XSSFWorkbook();//創(chuàng)建工作表 這里就不給它命令了 按照默認(rèn)的來(lái)Sheet sheet = workbook.createSheet();//寫(xiě)入數(shù)據(jù) 循環(huán)插入65536行數(shù)據(jù),03版的HSSF最多只能插入65536行for (int rowNum = 0; rowNum < 65536; rowNum++) {//循環(huán)創(chuàng)建行Row row = sheet.createRow(rowNum);for(int cellNum=0;cellNum<10;cellNum++){//循環(huán)插入列Cell cell = row.createCell(cellNum);//循環(huán)設(shè)置值cell.setCellValue(cellNum);}}System.out.println("生成excel表完畢");//037版本的后綴是xlsx//開(kāi)啟文件流FileOutputStream fileOutputStream = new FileOutputStream(path + "BigDateExcelWrite07.xlsx");//開(kāi)始寫(xiě)excelworkbook.write(fileOutputStream);//關(guān)閉流fileOutputStream.close();//結(jié)束時(shí)間long endTime = System.currentTimeMillis();//輸出花費(fèi)的時(shí)間System.out.println("花費(fèi)的時(shí)間:"+(double)(endTime - beginTime)/1000);} }雖然也運(yùn)行成功,但是可以明顯感覺(jué)到速度不如03版HSSF,但是可以存更多的數(shù)據(jù)
打開(kāi)excel查看發(fā)現(xiàn)數(shù)據(jù)到了65536停并沒(méi)有結(jié)束,說(shuō)明07版本XSSF上限不是65536,是可以存儲(chǔ)更多的,可以寫(xiě)更多的數(shù)據(jù)
如果我們正在查看同一個(gè)文件,但是又進(jìn)行其他操作,就會(huì)出現(xiàn)以下錯(cuò)誤,我們把我們正在查看的文件關(guān)閉讓它運(yùn)行,等運(yùn)行結(jié)束后再次打開(kāi)即可
07版本XSSF導(dǎo)入100000條數(shù)據(jù),把循環(huán)數(shù)改為100000即可
既然XSSF可以存這么多數(shù)據(jù),但是速度比較慢,有沒(méi)有方法可以?xún)?yōu)化效率呢(緩存,這個(gè)問(wèn)題也可以叫做如何給poi加速
它就是Workbook接口三個(gè)實(shí)現(xiàn)類(lèi)之一的SXSSFWorkbook,其他的兩個(gè)我們上面都有操作過(guò)
這時(shí)候需要用到我們的SXSSF
優(yōu)點(diǎn):可以寫(xiě)非常大的數(shù)據(jù)量.如100萬(wàn)條甚至更多,寫(xiě)速度非常快,占用更少的
注意
1 過(guò)程中會(huì)產(chǎn)生臨時(shí)文件,需要清理臨時(shí)文件
2 默認(rèn)由100條記錄被保存在內(nèi)存中,如果超過(guò)這數(shù)量,則最前面的數(shù)據(jù)被寫(xiě)入臨時(shí)文件,當(dāng)然緩存數(shù)量也可以自定義
3 如果自定義內(nèi)存中數(shù)據(jù)的數(shù)量,可以使用new SXSSFWorkbook(數(shù)量)
SXSSF循環(huán)插入100000條數(shù)據(jù)
運(yùn)行發(fā)現(xiàn),excel也正常生成了,但是它(SXSSF)的速度比XSSF快的多
查看我們的super
這就是我們的臨時(shí)文件,隨著我們把文件的關(guān)閉,臨時(shí)文件也會(huì)隨之消失
7 poi excel讀
1 03版poi excel讀
package com.wyh.Test;import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; 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.junit.Test;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilterInputStream;/*** @program: JavaExecl* @description: 03版poi讀* @author: 魏一鶴* @createDate: 2021-12-15 23:20**/public class BigDateExcelRead03 {//全局路徑,供我們操作使用方便static String path = "D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void BigDateExcelWrite03() throws Exception {//需要讀取,肯定需要流 所以這邊我們創(chuàng)建流FileInputStream filterInputStream = new FileInputStream(path+"用戶(hù)測(cè)試03.xls");// 1 創(chuàng)建工作簿 使用excel可以完成的操作這邊通過(guò)poi都可以完成//把我們的流放在工作簿用 用于讀取excel數(shù)據(jù)Workbook workbook = new HSSFWorkbook(filterInputStream);//2 獲取工作表 可以通過(guò)名稱(chēng)和下標(biāo)獲取工作表 這邊使用下標(biāo)獲取 0就是第一個(gè)工作表Sheet sheet = workbook.getSheetAt(0);//行列組成單元格//3 獲取行 下標(biāo)為0就是第一個(gè)Row row = sheet.getRow(0);//4 獲取列 下標(biāo)為0就是第一個(gè)Cell cell1 = row.getCell(0);Cell cell2 = row.getCell(1);//獲取單元格內(nèi)容// cell 有很多方法,獲取不同的數(shù)據(jù)需要用到不同的方法getStringCellValue獲取字符串//讀取值的時(shí)候 一定要只要數(shù)據(jù)類(lèi)型 根據(jù)不同的數(shù)據(jù)類(lèi)型使用不同的方法String stringCellValue = cell1.getStringCellValue();double numericCellValue = cell2.getNumericCellValue();System.out.println(stringCellValue);System.out.println(numericCellValue);//關(guān)閉流filterInputStream.close();} }
2 07版poi excel讀
只需要把引用對(duì)象(XSSF)和后綴(xlsx)改變即可
package com.wyh.Test;import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; 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.streaming.SXSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.junit.Test;import java.io.FileInputStream;/*** @program: JavaExecl* @description: 03版poi讀* @author: 魏一鶴* @createDate: 2021-12-15 23:20**/public class BigDateExcelRead07 {//全局路徑,供我們操作使用方便static String path = "D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void BigDateExcelWrite07() throws Exception {//需要讀取,肯定需要流 所以這邊我們創(chuàng)建流FileInputStream filterInputStream = new FileInputStream(path+"用戶(hù)測(cè)試07.xlsx");// 1 創(chuàng)建工作簿 使用excel可以完成的操作這邊通過(guò)poi都可以完成//把我們的流放在工作簿用 用于讀取excel數(shù)據(jù)Workbook workbook = new XSSFWorkbook(filterInputStream);//2 獲取工作表 可以通過(guò)名稱(chēng)和下標(biāo)獲取工作表 這邊使用下標(biāo)獲取 0就是第一個(gè)工作表Sheet sheet = workbook.getSheetAt(0);//行列組成單元格//3 獲取行 下標(biāo)為0就是第一個(gè)Row row = sheet.getRow(0);//4 獲取列 下標(biāo)為0就是第一個(gè)Cell cell1 = row.getCell(0);Cell cell2 = row.getCell(1);//獲取單元格內(nèi)容// cell 有很多方法,獲取不同的數(shù)據(jù)需要用到不同的方法getStringCellValue獲取字符串//讀取值的時(shí)候 一定要只要數(shù)據(jù)類(lèi)型 根據(jù)不同的數(shù)據(jù)類(lèi)型使用不同的方法String stringCellValue1 = cell1.getStringCellValue();String stringCellValue2 = cell2.getStringCellValue();System.out.println(stringCellValue1);System.out.println(stringCellValue2);//關(guān)閉流filterInputStream.close();} }
8 讀取不同的數(shù)據(jù)類(lèi)型
首先準(zhǔn)備一個(gè)多種數(shù)據(jù)類(lèi)型的excel
獲取全部表頭信息
獲取全部表頭數(shù)并且打印輸出
package com.wyh.Test;import org.apache.poi.hssf.usermodel.HSSFWorkbook; 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; import org.junit.Test;import javax.sql.RowSet; import java.io.FileInputStream;/*** @program: JavaExecl* @description: 讀取不同的excel數(shù)據(jù)類(lèi)型* @author: 魏一鶴* @createDate: 2021-12-16 23:42**/public class ReadManyInfo {//全局路徑,供我們操作使用方便static String path="D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void BigDateExcelWrite07() throws Exception {//需要讀取,肯定需要流 所以這邊我們創(chuàng)建流FileInputStream filterInputStream = new FileInputStream(path+"會(huì)員消費(fèi)商品明細(xì)表.xls");// 1 創(chuàng)建工作簿 使用excel可以完成的操作這邊通過(guò)poi都可以完成//把我們的流放在工作簿用 用于讀取excel數(shù)據(jù)Workbook workbook = new HSSFWorkbook(filterInputStream);//2 獲取工作表Sheet sheet = workbook.getSheetAt(0);//3獲取行(表頭)Row rowTitle = sheet.getRow(0); //其實(shí)這就是我們的表頭 最上面的部分//判斷行不為空才讀if(rowTitle!=null){//如果行不為空才去讀列的信息//getPhysicalNumberOfCells()獲取全部的列并且返回行數(shù)int cellCount = rowTitle.getPhysicalNumberOfCells();System.out.println("cellCount = " + cellCount);for (int cellNum = 0; cellNum<cellCount; cellNum++) {//得到每一行的數(shù)據(jù)Cell cell = rowTitle.getCell(cellNum);//判斷每一行是否為空 不為空再做處理if(cell!=null){//獲取全部行的數(shù)據(jù)類(lèi)型int cellType = cell.getCellType();//獲取行的值String stringCellValue = cell.getStringCellValue();//進(jìn)行輸出 這里就不換行了 直接一行顯示用豎線(xiàn)分割System.out.print(stringCellValue+"|");}}//打印完一行換行打印另外一行System.out.println();}//關(guān)閉流filterInputStream.close();} }
打印結(jié)果和我們的excel表頭內(nèi)容個(gè)數(shù)是完全對(duì)的上的
獲取表中內(nèi)容
比較復(fù)雜的就是不同的數(shù)據(jù)類(lèi)型進(jìn)行判斷,我們可以把這些提取成一個(gè)公用的方法
9 計(jì)算公式
首先需要準(zhǔn)備一個(gè)excel
需要獲取計(jì)算公式eval FormulaEvaluator
如果我們用沒(méi)有計(jì)算公式的行,那么不會(huì)有用
10 easyExcel寫(xiě)
特點(diǎn):阿里巴巴開(kāi)源的工具,代碼簡(jiǎn)化,占用內(nèi)存少,優(yōu)化OOM(內(nèi)存溢出異常)
1 pom引入依賴(lài)
由于pom底層也是使用的poi進(jìn)行處理,為了避免沖突,我們把pom引入的pom注釋掉
2 準(zhǔn)備一個(gè)實(shí)體類(lèi) 因?yàn)閑asyexcel根據(jù)實(shí)體類(lèi)自動(dòng)生成的表 效率非常的高
package com.wyh.entity;import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelProperty; import lombok.Data;import java.util.Date;/*** @program: JavaExecl* @description: easyExcel實(shí)體類(lèi) 可以用它生成excel* @author: 魏一鶴* @createDate: 2021-12-18 23:03**/ @Data public class DemoData {@ExcelProperty("字符串標(biāo)題")private String string;@ExcelProperty("日期標(biāo)題")private Date date;@ExcelProperty("數(shù)字標(biāo)題")private Double doubleData;/*** 忽略這個(gè)字段*/@ExcelIgnoreprivate String ignore; }它對(duì)應(yīng)生成的就是這樣
3 寫(xiě)一個(gè)基本的寫(xiě)入操作
完整的代碼
package com.wyh.Test;import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.metadata.WriteSheet; import com.wyh.entity.DemoData; import org.apache.commons.collections4.ListUtils; import org.junit.Test;import java.util.ArrayList; import java.util.Date; import java.util.List;/*** @program: JavaExecl* @description: easyExcel寫(xiě)操作* @author: 魏一鶴* @createDate: 2021-12-18 23:08**/public class EasyExcelWrite {//全局路徑,供我們操作使用方便static String path="D:\\Tools\\JavaWorkSpace\\JavaExecl\\";private List<DemoData> data() {List<DemoData> list = new ArrayList<DemoData>();for (int i = 0; i < 10; i++) {DemoData data = new DemoData();data.setString("字符串" + i);data.setDate(new Date());data.setDoubleData(0.56);list.add(data);}return list;}//根據(jù)list寫(xiě)入excel@Testpublic void simpleWrite() {// 寫(xiě)法1 JDK8+// since: 3.0.0-beta1//生成的文件名和文件所在位置String fileName =path+"easyExcel.xlsx";//開(kāi)始寫(xiě)入 這里說(shuō)下幾個(gè)參數(shù)//1 fileName 是一個(gè)io流 自動(dòng)生成excel//2 DemoData.class根據(jù)哪個(gè)類(lèi)的規(guī)則去生成excel//3 sheetName 生成的表的名字//4 進(jìn)行寫(xiě)出,寫(xiě)入到規(guī)則就是我們上面定義的方法循環(huán)EasyExcel.write(fileName,DemoData.class).sheet("模板").doWrite(data());} }運(yùn)行完畢之后發(fā)現(xiàn)已經(jīng)生成了,而且和我們想要的數(shù)據(jù)格式是一樣的
11 easyExcel讀
1 需要一個(gè)實(shí)體,我們已經(jīng)有了,可以直接用上面的DemoData
package com.wyh.entity;import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelProperty; import lombok.Data;import java.util.Date;/*** @program: JavaExecl* @description: easyExcel實(shí)體類(lèi) 可以用它生成excel* @author: 魏一鶴* @createDate: 2021-12-18 23:03**/ @Data public class DemoData {@ExcelProperty("字符串標(biāo)題")private String string;@ExcelProperty("日期標(biāo)題")private Date date;@ExcelProperty("數(shù)字標(biāo)題")private Double doubleData;/*** 忽略這個(gè)字段*/@ExcelIgnoreprivate String ignore; }2 需要一個(gè)監(jiān)聽(tīng)器
package com.wyh.Test;import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellExtra; import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.fastjson.JSON; import com.wyh.entity.DemoData; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory;import java.util.ArrayList; import java.util.List; import java.util.Map;/*** @program: JavaExecl* @description: easyExcel監(jiān)聽(tīng)器* @author: 魏一鶴* @createDate: 2021-12-18 23:30**/ // 有個(gè)很重要的點(diǎn) DemoDataListener 不能被spring管理,要每次讀取excel都要new,然后里面用到spring可以構(gòu)造方法傳進(jìn)去 public class DemoDataListener extends AnalysisEventListener<DemoData> {private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);/*** 每隔5條存儲(chǔ)數(shù)據(jù)庫(kù),實(shí)際使用中可以3000條,然后清理list ,方便內(nèi)存回收*/private static final int BATCH_COUNT = 5;List<DemoData> list = new ArrayList<DemoData>();/*** 假設(shè)這個(gè)是一個(gè)DAO,當(dāng)然有業(yè)務(wù)邏輯這個(gè)也可以是一個(gè)service。當(dāng)然如果不用存儲(chǔ)這個(gè)對(duì)象沒(méi)用。*/private DemoDAO demoDAO;public DemoDataListener() {// 這里是demo,所以隨便new一個(gè)。實(shí)際使用如果到了spring,請(qǐng)使用下面的有參構(gòu)造函數(shù)demoDAO = new DemoDAO();}/*** 如果使用了spring,請(qǐng)使用這個(gè)構(gòu)造方法。每次創(chuàng)建Listener的時(shí)候需要把spring管理的類(lèi)傳進(jìn)來(lái)** @param demoDAO*/public DemoDataListener(DemoDAO demoDAO) {this.demoDAO = demoDAO;}/*** 這個(gè)每一條數(shù)據(jù)解析都會(huì)來(lái)調(diào)用** @param data* one row value. Is is same as {@link AnalysisContext#readRowHolder()}* @param context*/@Overridepublic void invoke(DemoData data, AnalysisContext context) {System.out.println(JSON.toJSONString(data));list.add(data);System.out.println(list);// 達(dá)到BATCH_COUNT了,需要去存儲(chǔ)一次數(shù)據(jù)庫(kù),防止數(shù)據(jù)幾萬(wàn)條數(shù)據(jù)在內(nèi)存,容易OOMif (list.size() >= BATCH_COUNT) {saveData();// 存儲(chǔ)完成清理 listlist.clear();}}/*** 所有數(shù)據(jù)解析完成了 都會(huì)來(lái)調(diào)用** @param context*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 這里也要保存數(shù)據(jù),確保最后遺留的數(shù)據(jù)也存儲(chǔ)到數(shù)據(jù)庫(kù)saveData();LOGGER.info("所有數(shù)據(jù)解析完成!");}/*** 加上存儲(chǔ)數(shù)據(jù)庫(kù)*/private void saveData() {demoDAO.save(list);} }3 然后寫(xiě)一個(gè)基本的讀操作
package com.wyh.Test;import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelReader; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.fastjson.JSON; import com.wyh.entity.DemoData; import org.apache.commons.collections4.ListUtils; import org.junit.Test;import java.io.File; import java.util.List;/*** @program: JavaExecl* @description: excel讀數(shù)據(jù)* @author: 魏一鶴* @createDate: 2021-12-18 23:38**/public class EasyExcelRead {//全局路徑,供我們操作使用方便static String path="D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void simpleRead() {//文件路徑String fileName = path + "easyExcel.xlsx";//重點(diǎn)注意監(jiān)聽(tīng)器讀取的邏輯//fileName 文件//DemoData 類(lèi)規(guī)則//DemoDataListener 監(jiān)聽(tīng)器//sheet().doRead() 表的讀取EasyExcel.read(fileName,DemoData.class,new DemoDataListener()).sheet().doRead();}}啟動(dòng)發(fā)現(xiàn)全部數(shù)據(jù)被正常讀取到
4 總結(jié)下easyExcel的步驟
1 寫(xiě)入 根據(jù)固定的類(lèi)格式進(jìn)行寫(xiě)入
2 讀取 根據(jù)監(jiān)聽(tīng)器設(shè)置規(guī)則進(jìn)行讀取
本次poi和easyExcel操作excel先到此為止,后續(xù)會(huì)結(jié)合項(xiàng)目寫(xiě)導(dǎo)入導(dǎo)出數(shù)據(jù)庫(kù)的真實(shí)例子
總結(jié)
以上是生活随笔為你收集整理的poi和easyExcel基于Java操作Excel学习笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 用matlab解系统框图,第10章MAT
- 下一篇: 【程序人生】Java这么卷,你为什么还在