日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

poi和easyExcel基于Java操作Excel学习笔记

發布時間:2023/12/14 java 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 poi和easyExcel基于Java操作Excel学习笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1 學習前言

Excel和讀寫和文件的讀寫沒有本質的區別,都是屬于IO操作,我們使用原生的IO就能解決Excel的導入和導出,當然操作起來比較麻煩,性能也不高,這次我們就學習poi和easyExcel(它們都屬于第三方工具)的方式去基于Java和Mysql數據庫導入導出我們的Excel的數據

poi:Apache

easyExcel:阿里巴巴開源的工具

2 使用常用場景

1 將大量的數據導入為excel表格

2 將excel表中的信息錄入到數據庫(比如習題上傳)(也叫批量插入),大大減輕我們人工乃至網站的錄入量

開發中經常會涉及到對Excel的處理,如導入Excel,導出Excel到數據庫

目前操作excel比較流行的就是Apache POI和阿里巴巴的easyExcel

3 Apache POI

官網: https://poi.apache.org


Apache給我們提供的POI不僅可以操作excel格式,對于word,ppt,visio都是提供支持的,而且語法大概類似

HSSF是處理普通的excel的

XSSF是處理OOXML格式的excel的

值得注意點是,雖然HSSF和XSSF都可以處理excel,但是還是有差距

比如excel主要有兩個版本 03版和07版,其中03版的行數最多只能存65535行,07版的是沒有限制的

如果想要操作Word,那么使用HWPF

如果想要操作PPT,那么使用HSLF

如果想要操作Visio,那么使用HDGF

原生的POI使用起來比較麻煩,而且量大的時候會報OOM異常(out of memory的簡稱,稱之為內存溢出),但是現在很多市面上的工具底層也是會使用封裝POI的

4 easyExcel(阿里巴巴開源工具)

官網:https://github.com/alibaba/easyexcel

官方文檔:https://www.yuque.com/easyexcel/doc/easyexcel

easyExcel是阿里巴巴開源的一個對于excel處理工具(框架)以使用簡單,節省內存著稱

easyExcel能大大減少內存占用的主要原因是在解析excel中沒有將文件數據一次性全部加載到內存中,而是從磁盤上一行一行的讀取,逐個解析
由于POI比較原生比較復雜,我們后研發出新的(工具)框架easyExcel,它是阿里巴巴退出的對于POI的后續產品,并且對POI做了升級和優化,不會因為excel數據量過大引起oom異常(內存溢出),使我們用起來更加的方便(讀寫Excel只需要一行代碼!)

5 poi和easyExcel的不同

主要在于內存和操作過程

比如我們現在excel表有100W數據

1 poi是先把數據加載到內存,如果我們內存比較小,Java是會直接報OOM內存溢出異常,這時候就會有問題,但是easyExcel它就比較簡單只能,就算讀寫100W行數據,會一行一行的讀寫,不會直接全部解析

2poi會一次性全部讀取和返回execl表格的數據,但是easyExcel不會這樣,它沒有將文件數據一次性全部加載到內存中,而是從磁盤上一行一行的讀取,逐個解析

poi和easyExcel的本質上就是時間和空間的轉換,根據我們的需求自行選擇即可

6 poi excel寫

1 創建Java項目

2 pom引入依賴

<!--導入依賴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><!--單元測試--> <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version> </dependency>

3 本地創建兩個excel 分別是03版和07版

首先03版,它最多有65536行

但是07版的,是沒有限制的

他們對應的后綴也是不一樣的,03版本的xls,07版本的是xslx,這意味著操作它們的工具類也不相同.03版本用的是poi,07版用的則是poi-ooxml

4 Java的宗旨就是萬物皆對象,我們也要把excel當成我們的一個對象去處理

1 工作薄
首先我們打開的excel就是一個大對象,也叫工作簿,它包括以下內容

2 工作表
每一個sheet也是我們excel對象的屬性,也叫工作表,我們肯定是現有工作簿才會有工作表,而且會默認自帶sheet,也可以根據我們的需要自行添加sheet工作表

3 行
excel中有很多行,每一行也是我們excel對象的屬性(橫的叫行,豎的叫列)

4 列
excel中有很多列,每一列也是我們excel對象的屬性(橫的叫行,豎的叫列)

5 單元格
一行一列有很多個單元格,每一個單元格也是我們excel對象的屬性

創建我們的測試類,創建Workbook對象,按著ctrl點進去發現它是一個接口

點擊箭頭可以看到它的三個實現類



定義工作簿,工作表,行列,單元格,和我們手動創建excel是一樣的操作,只不過是用代碼來實現


03版本excel IO操作寫的全部代碼如下

package com.wyh.Test;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.joda.time.DateTime; import org.junit.Test;import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.util.Date;/*** @program: JavaExecl* @description: 寫excel 03版本* @author: 魏一鶴* @createDate: 2021-12-12 10:42**/public class ExcelWrite03 {//全局路徑,供我們操作使用方便static String path="D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void ExcelWrite03() throws Exception {//1創建一個工作簿Workbook workbook=new HSSFWorkbook();//2創建一個工作表 工作簿里面包含工作表,所以創建工作表要通過工作簿創建//默認的工作表是沒有名字的,需要我們手動賦值,和我們在excel中更改sheet工作表的名稱是一樣的 操作Sheet sheet=workbook.createSheet("用戶表");//3創建行 行也是在我們的表中存在的,所以需要用到表來創建//默認從0開始 也就是第一行Row row1 = sheet.createRow(0);//創建單元格 第一行的第一個數據 用坐標表示為(1,1)Cell cell11 = row1.createCell(0);//創建單元格 第一行的第二個數據 用坐標表示為(1,2)Cell cell12 = row1.createCell(1);//給單元格賦值cell11.setCellValue("姓名");cell12.setCellValue("魏一鶴");//創建第二行Row row2=sheet.createRow(1);//創建第二行的第一列Cell cell21 = row2.createCell(0);Cell cell22 = row2.createCell(1);//給單元格賦值(2.1)cell21.setCellValue("出生日期");//創建時間并且格式化String s = new DateTime().toString("yyyy-MM-dd HH:mm:ss");//給單元格賦值(2.2)cell22.setCellValue(s);//生成一張表 其實就是IO流操作 03版本就是使用xls文件結尾FileOutputStream fileOutputStream = new FileOutputStream(path + "用戶測試03.xls");//輸出工作簿workbook.write(fileOutputStream);//關閉流fileOutputStream.close();System.out.println("用戶測試03.xls生成完畢");} }

運行后發現,會在項目本地生成我們定義的excel,打開查看



03版和07版的區別如下

1 03版本有最大長度現在 07版本沒有

2 03版本后綴xls 07版本后綴xlsx

3 03版本使用的工具是HSSF,07版本使用的是XSSF

5 大數據繞導入導出(批量)

真實開發中,大多數就是大數據批量導入或者導出excel

大文件寫HSSF

缺點:最多只能處理65536行,否則會報內存溢出異常

優點:過程中寫入緩存,不操作磁盤,最后一次性寫入磁盤,速度快

大文件寫XSSF

缺點:寫數據時速度非常慢,非常消耗內存,也會發生內存溢出,比如100萬條

優點:可以寫較大的數據量,比如20萬條

03版本HSSF循環導入65536行數據(03版本最大行就是65536)

03版本HSSF循環插入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: 大數據量寫03版本* @author: 魏一鶴* @createDate: 2021-12-14 23:31**/public class BigDateExcelWrite03 {//全局路徑,供我們操作使用方便static String path = "D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void BigDateExcelWrite03() throws Exception {//開始時間 用于計算時間差long beginTime = System.currentTimeMillis();//創建工作簿 03版本使用HSSFWorkbook workbook = new HSSFWorkbook();//創建工作表 這里就不給它命令了 按照默認的來Sheet sheet = workbook.createSheet();//寫入數據 循環插入65536行數據,03版的HSSF最多只能插入65536行for (int rowNum = 0; rowNum < 65536; rowNum++) {//循環創建行Row row = sheet.createRow(rowNum);for(int cellNum=0;cellNum<10;cellNum++){//循環插入列Cell cell = row.createCell(cellNum);//循環設置值cell.setCellValue(cellNum);}}System.out.println("生成excel表完畢");//03版本的后綴是xls//開啟文件流FileOutputStream fileOutputStream = new FileOutputStream(path + "BigDateExcelWrite03.xlsx");//開始寫excelworkbook.write(fileOutputStream);//關閉流fileOutputStream.close();//結束時間long endTime = System.currentTimeMillis();//輸出花費的時間System.out.println("花費的時間:"+(double)(endTime - beginTime)/1000);} }

運行發現excel已經創建成功,速度也非常的快

打開查看
已知03版本xls最多存65536行,那么如果我們循環插入65537行會怎么樣呢? 保留源代碼,循環最大值設置為65537

再次運行發現會報錯

java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535)

07版本XSSF循環插入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: 大數據量寫03版本* @author: 魏一鶴* @createDate: 2021-12-14 23:31**/public class BigDateExcelWrite07 {//全局路徑,供我們操作使用方便static String path = "D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void BigDateExcelWrite07() throws Exception {//開始時間 用于計算時間差long beginTime = System.currentTimeMillis();//創建工作簿 07版本的使用XSSFWorkbook workbook = new XSSFWorkbook();//創建工作表 這里就不給它命令了 按照默認的來Sheet sheet = workbook.createSheet();//寫入數據 循環插入65536行數據,03版的HSSF最多只能插入65536行for (int rowNum = 0; rowNum < 65536; rowNum++) {//循環創建行Row row = sheet.createRow(rowNum);for(int cellNum=0;cellNum<10;cellNum++){//循環插入列Cell cell = row.createCell(cellNum);//循環設置值cell.setCellValue(cellNum);}}System.out.println("生成excel表完畢");//037版本的后綴是xlsx//開啟文件流FileOutputStream fileOutputStream = new FileOutputStream(path + "BigDateExcelWrite07.xlsx");//開始寫excelworkbook.write(fileOutputStream);//關閉流fileOutputStream.close();//結束時間long endTime = System.currentTimeMillis();//輸出花費的時間System.out.println("花費的時間:"+(double)(endTime - beginTime)/1000);} }

雖然也運行成功,但是可以明顯感覺到速度不如03版HSSF,但是可以存更多的數據

打開excel查看發現數據到了65536停并沒有結束,說明07版本XSSF上限不是65536,是可以存儲更多的,可以寫更多的數據

如果我們正在查看同一個文件,但是又進行其他操作,就會出現以下錯誤,我們把我們正在查看的文件關閉讓它運行,等運行結束后再次打開即可

java.io.FileNotFoundException: D:\Tools\JavaWorkSpace\JavaExecl\BigDateExcelWrite07.xlsx (另一個程序正在使用此文件,進程無法訪問。)

07版本XSSF導入100000條數據,把循環數改為100000即可


既然XSSF可以存這么多數據,但是速度比較慢,有沒有方法可以優化效率呢(緩存,這個問題也可以叫做如何給poi加速

它就是Workbook接口三個實現類之一的SXSSFWorkbook,其他的兩個我們上面都有操作過


這時候需要用到我們的SXSSF

優點:可以寫非常大的數據量.如100萬條甚至更多,寫速度非常快,占用更少的

注意
1 過程中會產生臨時文件,需要清理臨時文件
2 默認由100條記錄被保存在內存中,如果超過這數量,則最前面的數據被寫入臨時文件,當然緩存數量也可以自定義
3 如果自定義內存中數據的數量,可以使用new SXSSFWorkbook(數量)


SXSSF循環插入100000條數據

package com.wyh.Test;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.FileOutputStream;/*** @program: JavaExecl* @description: 大數據量寫03版本* @author: 魏一鶴* @createDate: 2021-12-14 23:31**/public class BigDateExcelWrite07Super {//全局路徑,供我們操作使用方便static String path = "D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void BigDateExcelWrite07Super() throws Exception {//開始時間 用于計算時間差long beginTime = System.currentTimeMillis();//創建工作簿 07版本的使用XSSFWorkbook workbook = new SXSSFWorkbook();//創建工作表 這里就不給它命令了 按照默認的來Sheet sheet = workbook.createSheet();//寫入數據 循環插入65536行數據,03版的HSSF最多只能插入65536行for (int rowNum = 0; rowNum < 100000; rowNum++) {//循環創建行Row row = sheet.createRow(rowNum);for(int cellNum=0;cellNum<10;cellNum++){//循環插入列Cell cell = row.createCell(cellNum);//循環設置值cell.setCellValue(cellNum);}}System.out.println("生成excel表完畢");//037版本的后綴是xlsx//開啟文件流FileOutputStream fileOutputStream = new FileOutputStream(path + "BigDateExcelWrite07Super.xlsx");//開始寫excelworkbook.write(fileOutputStream);//關閉流fileOutputStream.close();//由于SXSSF會產生臨時文件,這里我們需要清除下臨時文件((SXSSFWorkbook) workbook).dispose();//結束時間long endTime = System.currentTimeMillis();//輸出花費的時間System.out.println("花費的時間:"+(double)(endTime - beginTime)/1000);} }

運行發現,excel也正常生成了,但是它(SXSSF)的速度比XSSF快的多

查看我們的super

這就是我們的臨時文件,隨著我們把文件的關閉,臨時文件也會隨之消失

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 {//需要讀取,肯定需要流 所以這邊我們創建流FileInputStream filterInputStream = new FileInputStream(path+"用戶測試03.xls");// 1 創建工作簿 使用excel可以完成的操作這邊通過poi都可以完成//把我們的流放在工作簿用 用于讀取excel數據Workbook workbook = new HSSFWorkbook(filterInputStream);//2 獲取工作表 可以通過名稱和下標獲取工作表 這邊使用下標獲取 0就是第一個工作表Sheet sheet = workbook.getSheetAt(0);//行列組成單元格//3 獲取行 下標為0就是第一個Row row = sheet.getRow(0);//4 獲取列 下標為0就是第一個Cell cell1 = row.getCell(0);Cell cell2 = row.getCell(1);//獲取單元格內容// cell 有很多方法,獲取不同的數據需要用到不同的方法getStringCellValue獲取字符串//讀取值的時候 一定要只要數據類型 根據不同的數據類型使用不同的方法String stringCellValue = cell1.getStringCellValue();double numericCellValue = cell2.getNumericCellValue();System.out.println(stringCellValue);System.out.println(numericCellValue);//關閉流filterInputStream.close();} }



2 07版poi excel讀

只需要把引用對象(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 {//需要讀取,肯定需要流 所以這邊我們創建流FileInputStream filterInputStream = new FileInputStream(path+"用戶測試07.xlsx");// 1 創建工作簿 使用excel可以完成的操作這邊通過poi都可以完成//把我們的流放在工作簿用 用于讀取excel數據Workbook workbook = new XSSFWorkbook(filterInputStream);//2 獲取工作表 可以通過名稱和下標獲取工作表 這邊使用下標獲取 0就是第一個工作表Sheet sheet = workbook.getSheetAt(0);//行列組成單元格//3 獲取行 下標為0就是第一個Row row = sheet.getRow(0);//4 獲取列 下標為0就是第一個Cell cell1 = row.getCell(0);Cell cell2 = row.getCell(1);//獲取單元格內容// cell 有很多方法,獲取不同的數據需要用到不同的方法getStringCellValue獲取字符串//讀取值的時候 一定要只要數據類型 根據不同的數據類型使用不同的方法String stringCellValue1 = cell1.getStringCellValue();String stringCellValue2 = cell2.getStringCellValue();System.out.println(stringCellValue1);System.out.println(stringCellValue2);//關閉流filterInputStream.close();} }


8 讀取不同的數據類型

首先準備一個多種數據類型的excel


獲取全部表頭信息

row.getPhysicalNumberOfCells() //獲取全部的列并返回行數

獲取全部表頭數并且打印輸出

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數據類型* @author: 魏一鶴* @createDate: 2021-12-16 23:42**/public class ReadManyInfo {//全局路徑,供我們操作使用方便static String path="D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void BigDateExcelWrite07() throws Exception {//需要讀取,肯定需要流 所以這邊我們創建流FileInputStream filterInputStream = new FileInputStream(path+"會員消費商品明細表.xls");// 1 創建工作簿 使用excel可以完成的操作這邊通過poi都可以完成//把我們的流放在工作簿用 用于讀取excel數據Workbook workbook = new HSSFWorkbook(filterInputStream);//2 獲取工作表Sheet sheet = workbook.getSheetAt(0);//3獲取行(表頭)Row rowTitle = sheet.getRow(0); //其實這就是我們的表頭 最上面的部分//判斷行不為空才讀if(rowTitle!=null){//如果行不為空才去讀列的信息//getPhysicalNumberOfCells()獲取全部的列并且返回行數int cellCount = rowTitle.getPhysicalNumberOfCells();System.out.println("cellCount = " + cellCount);for (int cellNum = 0; cellNum<cellCount; cellNum++) {//得到每一行的數據Cell cell = rowTitle.getCell(cellNum);//判斷每一行是否為空 不為空再做處理if(cell!=null){//獲取全部行的數據類型int cellType = cell.getCellType();//獲取行的值String stringCellValue = cell.getStringCellValue();//進行輸出 這里就不換行了 直接一行顯示用豎線分割System.out.print(stringCellValue+"|");}}//打印完一行換行打印另外一行System.out.println();}//關閉流filterInputStream.close();} }


打印結果和我們的excel表頭內容個數是完全對的上的

獲取表中內容

row.getPhysicalNumberOfCells() //獲取全部的列

比較復雜的就是不同的數據類型進行判斷,我們可以把這些提取成一個公用的方法


package com.wyh.Test;import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFDateUtil; 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.joda.time.DateTime; import org.junit.Test;import javax.sql.RowSet; import java.io.FileInputStream; import java.util.Date;/*** @program: JavaExecl* @description: 讀取不同的excel數據類型* @author: 魏一鶴* @createDate: 2021-12-16 23:42**/public class ReadManyInfo {//全局路徑,供我們操作使用方便static String path="D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void BigDateExcelWrite07() throws Exception {//需要讀取,肯定需要流 所以這邊我們創建流FileInputStream filterInputStream = new FileInputStream(path+"會員消費商品明細表.xls");switchDataType(filterInputStream);}public void switchDataType( FileInputStream filterInputStream ) throws Exception {// 1 創建工作簿 使用excel可以完成的操作這邊通過poi都可以完成//把我們的流放在工作簿用 用于讀取excel數據Workbook workbook = new HSSFWorkbook(filterInputStream);//2 獲取工作表Sheet sheet = workbook.getSheetAt(0);//3獲取行(表頭)Row rowTitle = sheet.getRow(0); //其實這就是我們的表頭 最上面的部分//判斷行不為空才讀if(rowTitle!=null){//如果行不為空才去讀列的信息//getPhysicalNumberOfCells()獲取全部的列并且返回行數int cellCount = rowTitle.getPhysicalNumberOfCells();System.out.println("cellCount = " + cellCount);for (int cellNum = 0; cellNum<cellCount; cellNum++) {//得到每一行的數據Cell cell = rowTitle.getCell(cellNum);//判斷每一行是否為空 不為空再做處理if(cell!=null){//獲取全部行的數據類型int cellType = cell.getCellType();//獲取行的值String stringCellValue = cell.getStringCellValue();//進行輸出 這里就不換行了 直接一行顯示用豎線分割System.out.print(stringCellValue+"|");}}//打印完一行換行打印另外一行System.out.println();}//獲取表中的內容int rowCount = sheet.getPhysicalNumberOfRows();//循環獲取數據for (int rowNum = 0; rowNum < rowCount; rowNum++) {Row row = sheet.getRow(rowNum);//不為空再做處理if(row!=null){//讀取行中的列 getPhysicalNumberOfCells獲取全部的列int cellCount = rowTitle.getPhysicalNumberOfCells();for (int cellNum = 0; cellNum < cellCount; cellNum++) {System.out.print("["+(rowNum+1)+"-"+(cellNum + 1)+"]");//獲取數據Cell cell = row.getCell(cellNum);//因為不知道列的數據類型 所以這里我們要匹配數據類型//如果不為空if(cell != null){//獲取類型int cellType = cell.getCellType();String cellValue="";//判斷cell的數據類型switch (cellType) {case HSSFCell.CELL_TYPE_STRING://字符串System.out.print("【STRING】");cellValue = cell.getStringCellValue();break;case HSSFCell.CELL_TYPE_BOOLEAN://布爾System.out.print("【BOOLEAN】");cellValue = String.valueOf(cell.getBooleanCellValue());break;case HSSFCell.CELL_TYPE_BLANK://System.out.print("【BLANK】");break;case HSSFCell.CELL_TYPE_NUMERIC:System.out.print("【NUMERIC】");//cellValue = String.valueOf(cell.getNumericCellValue());if (HSSFDateUtil.isCellDateFormatted(cell)) {//日期System.out.print("【日期】");Date date = cell.getDateCellValue();cellValue = new DateTime(date).toString("yyyy-MM-dd");} else {// 不是日期格式,則防止當數字過長時以科學計數法顯示System.out.print("【轉換成字符串】");cell.setCellType(HSSFCell.CELL_TYPE_STRING);cellValue = cell.toString();}break;case Cell.CELL_TYPE_ERROR:System.out.print("【數據類型錯誤】");break;}System.out.println(cellValue);}}}}//關閉流filterInputStream.close();} }

9 計算公式

首先需要準備一個excel

需要獲取計算公式eval FormulaEvaluator


如果我們用沒有計算公式的行,那么不會有用


package com.wyh.Test;import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; 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.*; import org.junit.Test;import java.io.FileInputStream; import java.io.FileNotFoundException;/*** @program: JavaExecl* @description: excel計算公式* @author: 魏一鶴* @createDate: 2021-12-18 00:03**/public class ExcelCalculation {//全局路徑,供我們操作使用方便static String path="D:\\Tools\\JavaWorkSpace\\JavaExecl\\";@Testpublic void testFormula() throws Exception {//首先還是要獲取路徑FileInputStream fileInputStream = new FileInputStream(path + "計算公式.xls");//讀取文件Workbook workbook = new HSSFWorkbook(fileInputStream);//讀取表Sheet sheet = workbook.getSheetAt(0);//根據表拿出數據//因為我們的需要計算的單元格在第五行 從0開始的 所以下標為4//如果我們用沒有計算公式的行,那么不會有用Row row = sheet.getRow(4);//(第一行 4,1)Cell cell = row.getCell(0);//拿到計算公式 evalFormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator((HSSFWorkbook)workbook);//輸出單元格的內容//獲取類型進行便利int cellType = cell.getCellType();switch (cellType){case Cell.CELL_TYPE_FORMULA://獲取公式String cellFormula = cell.getCellFormula();System.out.println(cellFormula);//計算CellValue evaValue=formulaEvaluator.evaluate(cell);String cellValue = evaValue.formatAsString();System.out.println(cellValue);//結束循環break;}}}

10 easyExcel寫

特點:阿里巴巴開源的工具,代碼簡化,占用內存少,優化OOM(內存溢出異常)

1 pom引入依賴
由于pom底層也是使用的poi進行處理,為了避免沖突,我們把pom引入的pom注釋掉

<!--easyExcel依賴--> <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.0-beta2</version> </dependency><!--導入依賴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>-->

2 準備一個實體類 因為easyexcel根據實體類自動生成的表 效率非常的高

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實體類 可以用它生成excel* @author: 魏一鶴* @createDate: 2021-12-18 23:03**/ @Data public class DemoData {@ExcelProperty("字符串標題")private String string;@ExcelProperty("日期標題")private Date date;@ExcelProperty("數字標題")private Double doubleData;/*** 忽略這個字段*/@ExcelIgnoreprivate String ignore; }

它對應生成的就是這樣


3 寫一個基本的寫入操作

//根據list寫入excel @Test public void simpleWrite() {// 寫法1 JDK8+// since: 3.0.0-beta1//生成的文件名和文件所在位置String fileName =path+"easyExcel.xlsx";//開始寫入 這里說下幾個參數//1 fileName 是一個io流 自動生成excel//2 DemoData.class根據哪個類的規則去生成excel//3 sheetName 生成的表的名字//4 進行寫出,寫入到規則就是我們上面定義的方法循環EasyExcel.write(fileName,DemoData.class).sheet("模板").doWrite(data()); }

完整的代碼

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寫操作* @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;}//根據list寫入excel@Testpublic void simpleWrite() {// 寫法1 JDK8+// since: 3.0.0-beta1//生成的文件名和文件所在位置String fileName =path+"easyExcel.xlsx";//開始寫入 這里說下幾個參數//1 fileName 是一個io流 自動生成excel//2 DemoData.class根據哪個類的規則去生成excel//3 sheetName 生成的表的名字//4 進行寫出,寫入到規則就是我們上面定義的方法循環EasyExcel.write(fileName,DemoData.class).sheet("模板").doWrite(data());} }

運行完畢之后發現已經生成了,而且和我們想要的數據格式是一樣的

11 easyExcel讀

1 需要一個實體,我們已經有了,可以直接用上面的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實體類 可以用它生成excel* @author: 魏一鶴* @createDate: 2021-12-18 23:03**/ @Data public class DemoData {@ExcelProperty("字符串標題")private String string;@ExcelProperty("日期標題")private Date date;@ExcelProperty("數字標題")private Double doubleData;/*** 忽略這個字段*/@ExcelIgnoreprivate String ignore; }

2 需要一個監聽器

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監聽器* @author: 魏一鶴* @createDate: 2021-12-18 23:30**/ // 有個很重要的點 DemoDataListener 不能被spring管理,要每次讀取excel都要new,然后里面用到spring可以構造方法傳進去 public class DemoDataListener extends AnalysisEventListener<DemoData> {private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);/*** 每隔5條存儲數據庫,實際使用中可以3000條,然后清理list ,方便內存回收*/private static final int BATCH_COUNT = 5;List<DemoData> list = new ArrayList<DemoData>();/*** 假設這個是一個DAO,當然有業務邏輯這個也可以是一個service。當然如果不用存儲這個對象沒用。*/private DemoDAO demoDAO;public DemoDataListener() {// 這里是demo,所以隨便new一個。實際使用如果到了spring,請使用下面的有參構造函數demoDAO = new DemoDAO();}/*** 如果使用了spring,請使用這個構造方法。每次創建Listener的時候需要把spring管理的類傳進來** @param demoDAO*/public DemoDataListener(DemoDAO demoDAO) {this.demoDAO = demoDAO;}/*** 這個每一條數據解析都會來調用** @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);// 達到BATCH_COUNT了,需要去存儲一次數據庫,防止數據幾萬條數據在內存,容易OOMif (list.size() >= BATCH_COUNT) {saveData();// 存儲完成清理 listlist.clear();}}/*** 所有數據解析完成了 都會來調用** @param context*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 這里也要保存數據,確保最后遺留的數據也存儲到數據庫saveData();LOGGER.info("所有數據解析完成!");}/*** 加上存儲數據庫*/private void saveData() {demoDAO.save(list);} }

3 然后寫一個基本的讀操作

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讀數據* @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";//重點注意監聽器讀取的邏輯//fileName 文件//DemoData 類規則//DemoDataListener 監聽器//sheet().doRead() 表的讀取EasyExcel.read(fileName,DemoData.class,new DemoDataListener()).sheet().doRead();}}

啟動發現全部數據被正常讀取到

4 總結下easyExcel的步驟

1 寫入 根據固定的類格式進行寫入
2 讀取 根據監聽器設置規則進行讀取

本次poi和easyExcel操作excel先到此為止,后續會結合項目寫導入導出數據庫的真實例子

總結

以上是生活随笔為你收集整理的poi和easyExcel基于Java操作Excel学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。