POI和EasyExcel的使用
POI是什么
Apache POI是Apache軟件基金會的開放源碼函式庫,POI提供API給Java程序對Microsoft Office格式檔案讀和寫的功能.可以用於把數據導出為excel表格或者是把excel表的數據錄入到數據庫中.
依賴
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
excel對象
-
工作簿(文件)
-
工作表(sheet)
-
行
-
列
表寫入
@Test
public void test1() throws IOException {
//HSSFWorkbook為03版excel表,07版使用XSSFWorkbook
Workbook workbook = new HSSFWorkbook();
Sheet sheet = workbook.createSheet("my_sheet");
//第一行
Row row_1 = sheet.createRow(0);
//第一行的第一個單元格
Cell cell_1_1 = row_1.createCell(0);
cell_1_1.setCellValue("姓名");
Cell cell_1_2 = row_1.createCell(1);
cell_1_2.setCellValue("野原新之助");
Row row_2 = sheet.createRow(1);
Cell cell_2_1 = row_2.createCell(0);
cell_2_1.setCellValue("年齡");
Cell cell_2_2 = row_2.createCell(1);
cell_2_2.setCellValue(5);
//03版excel表結尾為xls,07版excel表結尾為xlsx
FileOutputStream stream = new FileOutputStream(PATH + "test1.xls");
workbook.write(stream);
stream.close();
workbook.close();
}
數據批量導入:
- HSSF
- 最多只能處理65536行數據
- 過程中寫入緩存,不操作磁盤,最后一次性寫入磁盤,速度快
- XSSF
- 速度慢,耗內存,也會發生內存溢出
- 可以寫較大的數據量
- SXSSF
- 加速版的XSSF
- 過程中會產生臨時文件,需要清理臨時文件
- 默認100條記錄保存在內存中,超過寫入
- 如果要自定義內存中的數據量:new SXSSFWorkBook(數量)
- 清除臨時文件:==((SXSSFWorkBook)workBook).dispose()
表讀取
@Test
public void test1() throws IOException {
FileInputStream stream = new FileInputStream(PATH + "test1.xls");
//使用對應的workbook打開對應版本的excel表
Workbook workbook = new HSSFWorkbook(stream);
Sheet sheet = workbook.getSheetAt(0);
for (int rowNum = 0; rowNum < 2; rowNum++) {
Row row = sheet.getRow(rowNum);
for (int cellNum = 0; cellNum < 2; cellNum++) {
Cell cell = row.getCell(cellNum);
System.out.println(cell);
}
}
stream.close();
workbook.close();
}
EasyExcel是什么
Java解析、生成Excel比較有名的框架有Apache poi、jxl。但他們都存在一個嚴重的問題就是非常的耗內存,poi有一套SAX模式的API可以一定程度的解決一些內存溢出的問題,但POI還是有一些缺陷,比如07版Excel解壓縮以及解壓后存儲都是在內存中完成的,內存消耗依然很大。easyexcel重寫了poi對07版Excel的解析,能夠原本一個3M的excel用POI sax依然需要100M左右內存降低到幾M,並且再大的excel不會出現內存溢出,03版依賴POI的sax模式。在上層做了模型轉換的封裝,讓使用者更加簡單方便
依賴
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
簡單使用
實體類
@Data
public class User {
@ExcelProperty("用戶名")
private String username;
@ExcelIgnore
private String password;
@ExcelProperty("生日")
private Date birthday;
@ExcelProperty("余額")
private Double money;
}
表寫入
private List<User> user(){
List<User> list = new ArrayList<User>();
for (int i = 0; i < 10; i++) {
User user = new User();
user.setUsername("用戶" + i);
user.setPassword(String.valueOf(Math.random()));
user.setBirthday(new Date());
user.setMoney(3.14);
list.add(user);
}
return list;
}
@Test
public void simpleWrite() {
// 寫法1
String fileName = PATH + "user1.xlsx";
// 這里 需要指定寫用哪個class去寫,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉
// 如果這里想使用03 則 傳入excelType參數即可
EasyExcel.write(fileName, User.class).sheet("自定義sheet名").doWrite(user());
// 寫法2
fileName = PATH + "user2.xlsx";
// 這里 需要指定寫用哪個class去寫
ExcelWriter excelWriter = null;
try {
excelWriter = EasyExcel.write(fileName, User.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet("用戶表").build();
excelWriter.write(user(), writeSheet);
} finally {
// 千萬別忘記finish 會幫忙關閉流
if (excelWriter != null) {
excelWriter.finish();
}
}
}
持久層
public class DemoDAO {
public void save(List<User> list) {
System.out.println("list->保存到數據庫!");
}
}
監聽器
// 有個很重要的點 DemoDataListener 不能被spring管理,要每次讀取excel都要new,然后里面用到spring可以構造方法傳進去
public class DemoDataListener extends AnalysisEventListener<User> {
private static final int BATCH_COUNT = 5;
List<User> list = new ArrayList<User>();
private DemoDAO demoDAO;
public DemoDataListener() {
// 這里是demo,所以隨便new一個。實際使用如果到了spring,請使用下面的有參構造函數
demoDAO = new DemoDAO();
}
public DemoDataListener(DemoDAO demoDAO) {
this.demoDAO = demoDAO;
}
@Override
public void invoke(User data, AnalysisContext context) {
System.out.println("解析到一條數據:" + JSON.toJSONString(data));
list.add(data);
// 達到BATCH_COUNT了,需要去存儲一次數據庫,防止數據幾萬條數據在內存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存儲完成清理 list
list.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 這里也要保存數據,確保最后遺留的數據也存儲到數據庫
saveData();
System.out.println("所有數據解析完成!");
}
private void saveData() {
System.out.println(list.size() + "條數據,開始存儲數據庫!");
demoDAO.save(list);
System.out.println("存儲數據庫成功!");
}
}
表讀取
@Test
public void simpleRead() {
// 有個很重要的點 DemoDataListener 不能被spring管理,要每次讀取excel都要new,然后里面用到spring可以構造方法傳進去
// 寫法1:
String fileName = PATH + "user1.xlsx";
// 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet 文件流會自動關閉
EasyExcel.read(fileName, User.class, new DemoDataListener()).sheet().doRead();
// 寫法2:
fileName = PATH + "user2.xlsx";
ExcelReader excelReader = null;
try {
excelReader = EasyExcel.read(fileName, User.class, new DemoDataListener()).build();
ReadSheet readSheet = EasyExcel.readSheet(0).build();
excelReader.read(readSheet);
} finally {
if (excelReader != null) {
// 這里千萬別忘記關閉,讀的時候會創建臨時文件,到時磁盤會崩的
excelReader.finish();
}
}
}