本文目录导读:

在Java中导入Excel文件,常用的方案主要有三种:Apache POI、EasyExcel(阿里开源的)和 JXL(已过时,不推荐)。
这里给你提供目前最主流的两种方案:Apache POI(功能全面,适合复杂处理)和 EasyExcel(性能优秀,适合大数据量,内存占用低)。
使用 Apache POI (最经典、最全面)
Apache POI 可以处理 .xls (HSSFWorkbook) 和 .xlsx (XSSFWorkbook) 格式。
添加 Maven 依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version> <!-- 使用较新版本 -->
</dependency>
核心代码示例(读取 .xlsx 文件)
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ImportExcelByPOI {
public static List<List<String>> readExcel(String filePath) {
List<List<String>> result = new ArrayList<>();
try (InputStream is = new FileInputStream(filePath);
Workbook workbook = new XSSFWorkbook(is)) { // 支持 .xlsx
// 获取第一个工作表
Sheet sheet = workbook.getSheetAt(0);
if (sheet == null) {
return result;
}
// 遍历每一行
for (Row row : sheet) {
// 跳过空行
if (row == null) continue;
List<String> rowData = new ArrayList<>();
// 遍历单元格
for (Cell cell : row) {
// 根据单元格类型获取数据
String cellValue = getCellValue(cell);
rowData.add(cellValue);
}
result.add(rowData);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
// 处理单元格数据类型的工具方法
private static String getCellValue(Cell cell) {
if (cell == null) return "";
return switch (cell.getCellType()) {
case STRING -> cell.getStringCellValue();
case NUMERIC -> {
// 如果是日期格式,处理为日期字符串,否则处理为数字
if (DateUtil.isCellDateFormatted(cell)) {
yield cell.getLocalDateTimeCellValue().toString(); // 或者自定义格式化
} else {
// 避免科学计数法,转为字符串
double value = cell.getNumericCellValue();
if (value == Math.floor(value) && !Double.isInfinite(value)) {
yield String.valueOf((long) value);
} else {
yield String.valueOf(value);
}
}
}
case BOOLEAN -> String.valueOf(cell.getBooleanCellValue());
case FORMULA -> cell.getCellFormula(); // 公式结果可以获取计算后的值
case BLANK -> "";
default -> "";
};
}
public static void main(String[] args) {
String filePath = "test.xlsx"; // 你的文件路径
List<List<String>> data = readExcel(filePath);
for (List<String> row : data) {
System.out.println(row);
}
}
}
POI 的优缺点:
- ✅ 优点:功能极其强大,能处理各种复杂的Excel格式(公式、样式、批注、图表等)。
- ❌ 缺点:内存消耗较大,如果一次性读取一个5万行的大文件,可能会触发
OutOfMemoryError。
使用 EasyExcel (推荐,高性能、低内存)
EasyExcel 是阿里巴巴开源的工具,对POI进行了封装,解决了大文件OOM问题,它是目前Java后端处理Excel的首选方案。
添加 Maven 依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>4.0.1</version> <!-- 使用较新版本 -->
</dependency>
核心代码示例(最简单的读取方式)
方式A:同步读取(小文件,一次性读进内存)
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import java.util.List;
public class ImportExcelByEasyExcel {
public static void main(String[] args) {
String fileName = "test.xlsx";
// 同步读取:数据量不大时直接用
List<Object> list = EasyExcel.read(fileName).sheet().doReadSync();
for (Object obj : list) {
// obj 默认是 List<String>,每一行的数据
System.out.println(obj);
}
}
}
方式B:异步读取(推荐,支持大文件,逐行处理)
需要定义一个监听器类 DemoDataListener,继承 ReadListener<DemoData>。
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
// 1. 定义数据模型(可选,但强烈推荐)
public class DemoData {
private String name;
private Integer age;
private String email;
// 必须要有 getter/setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
// 2. 定义监听器
public class DemoDataListener implements ReadListener<DemoData> {
private static final Logger log = LoggerFactory.getLogger(DemoDataListener.class);
private static final int BATCH_COUNT = 100; // 每100条批量处理一次
private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
private final DemoService demoService; // 可以注入业务Service
public DemoDataListener() {
this.demoService = new DemoService(); // 实际项目用 Spring 自动注入
}
@Override
public void invoke(DemoData data, AnalysisContext context) {
log.info("读取到一条数据:{}", data);
cachedDataList.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止内存溢出
if (cachedDataList.size() >= BATCH_COUNT) {
saveData(); // 批量处理
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); // 清空列表
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 处理最后一批不满BATCH_COUNT的数据
saveData();
log.info("所有数据解析完成!");
}
private void saveData() {
log.info("{}条数据,开始存储数据库!", cachedDataList.size());
demoService.saveBatch(cachedDataList); // 批量插入数据库
log.info("存储数据库成功!");
}
// 如果第一行是表头,可以用这个方法来获取表头信息
@Override
public void invokeHead(Map<Integer, ReadCellHead> headMap, AnalysisContext context) {
log.info("解析到表头:{}", headMap);
}
}
// 3. 使用
public static void main(String[] args) {
String fileName = "test.xlsx";
// 核心调用:只需一行
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
}
EasyExcel 的优缺点:
- ✅ 优点:
- 内存占用极低(使用行缓存,不会一次性将整个文件读入内存)。
- 使用简单,一行代码完成读取。
- 支持模型映射(注解
@ExcelProperty)。 - 性能好。
- ❌ 缺点:
对格式的处理不如POI细致(如样式、图表等),但日常数据导入场景完全够用。
总结与建议
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 日常数据导入 (几千行以内,简单格式) | EasyExcel | 代码简洁,内存占用低。 |
| 大数据量导入 (几万行以上) | EasyExcel (必须使用异步监听模式) | POI会OOM,EasyExcel是唯一选择。 |
| 需要处理复杂的Excel格式 (公式、图表、透视表、样式) | Apache POI | 功能最底层、最全面。 |
| 需要处理 .xls (2003旧格式) | POI 或 EasyExcel | 两者都支持,但POI支持更完善。 |
一句话总结:做Java后端导入Excel,首选 EasyExcel。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播