Looly 5 years ago
parent
commit
3bca95c34a

+ 1 - 0
CHANGELOG.md

@@ -15,6 +15,7 @@
 * 【core   】     增加StrUtil.removeAny方法(issue#923@Github)
 * 【db     】     增加部分Connection参数支持(issue#924@Github)
 * 【core   】     FileUtil增加别名方法(pr#926@Github)
+* 【poi    】     EcelReader中增加read重载,提供每个单元格单独处理的方法(issue#I1JZTL@Gitee)
 
 ### Bug修复
 * 【json   】     修复append方法导致的JSONConfig传递失效问题(issue#906@Github)

+ 112 - 62
hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelReader.java

@@ -9,9 +9,11 @@ import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.poi.excel.cell.CellEditor;
+import cn.hutool.poi.excel.cell.CellHandler;
 import cn.hutool.poi.excel.cell.CellUtil;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.extractor.ExcelExtractor;
+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;
@@ -28,25 +30,32 @@ import java.util.Map;
 /**
  * Excel读取器<br>
  * 读取Excel工作簿
- * 
+ *
  * @author Looly
  * @since 3.1.0
  */
 public class ExcelReader extends ExcelBase<ExcelReader> {
 
-	/** 是否忽略空行 */
+	/**
+	 * 是否忽略空行
+	 */
 	private boolean ignoreEmptyRow = true;
-	/** 单元格值处理接口 */
+	/**
+	 * 单元格值处理接口
+	 */
 	private CellEditor cellEditor;
-	/** 标题别名 */
+	/**
+	 * 标题别名
+	 */
 	private Map<String, String> headerAlias = new HashMap<>();
 
 	// ------------------------------------------------------------------------------------------------------- Constructor start
+
 	/**
 	 * 构造
-	 * 
+	 *
 	 * @param excelFilePath Excel文件路径,绝对路径或相对于ClassPath路径
-	 * @param sheetIndex sheet序号,0表示第一个sheet
+	 * @param sheetIndex    sheet序号,0表示第一个sheet
 	 */
 	public ExcelReader(String excelFilePath, int sheetIndex) {
 		this(FileUtil.file(excelFilePath), sheetIndex);
@@ -54,8 +63,8 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 构造
-	 * 
-	 * @param bookFile Excel文件
+	 *
+	 * @param bookFile   Excel文件
 	 * @param sheetIndex sheet序号,0表示第一个sheet
 	 */
 	public ExcelReader(File bookFile, int sheetIndex) {
@@ -64,8 +73,8 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 构造
-	 * 
-	 * @param bookFile Excel文件
+	 *
+	 * @param bookFile  Excel文件
 	 * @param sheetName sheet名,第一个默认是sheet1
 	 */
 	public ExcelReader(File bookFile, String sheetName) {
@@ -74,9 +83,9 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 构造
-	 * 
-	 * @param bookStream Excel文件的流
-	 * @param sheetIndex sheet序号,0表示第一个sheet
+	 *
+	 * @param bookStream     Excel文件的流
+	 * @param sheetIndex     sheet序号,0表示第一个sheet
 	 * @param closeAfterRead 读取结束是否关闭流
 	 */
 	public ExcelReader(InputStream bookStream, int sheetIndex, boolean closeAfterRead) {
@@ -85,9 +94,9 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 构造
-	 * 
-	 * @param bookStream Excel文件的流
-	 * @param sheetName sheet名,第一个默认是sheet1
+	 *
+	 * @param bookStream     Excel文件的流
+	 * @param sheetName      sheet名,第一个默认是sheet1
 	 * @param closeAfterRead 读取结束是否关闭流
 	 */
 	public ExcelReader(InputStream bookStream, String sheetName, boolean closeAfterRead) {
@@ -96,8 +105,8 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 构造
-	 * 
-	 * @param book {@link Workbook} 表示一个Excel文件
+	 *
+	 * @param book       {@link Workbook} 表示一个Excel文件
 	 * @param sheetIndex sheet序号,0表示第一个sheet
 	 */
 	public ExcelReader(Workbook book, int sheetIndex) {
@@ -106,8 +115,8 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 构造
-	 * 
-	 * @param book {@link Workbook} 表示一个Excel文件
+	 *
+	 * @param book      {@link Workbook} 表示一个Excel文件
 	 * @param sheetName sheet名,第一个默认是sheet1
 	 */
 	public ExcelReader(Workbook book, String sheetName) {
@@ -116,7 +125,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 构造
-	 * 
+	 *
 	 * @param sheet Excel中的sheet
 	 */
 	public ExcelReader(Sheet sheet) {
@@ -125,9 +134,10 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 	// ------------------------------------------------------------------------------------------------------- Constructor end
 
 	// ------------------------------------------------------------------------------------------------------- Getters and Setters start
+
 	/**
 	 * 是否忽略空行
-	 * 
+	 *
 	 * @return 是否忽略空行
 	 */
 	public boolean isIgnoreEmptyRow() {
@@ -136,7 +146,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 设置是否忽略空行
-	 * 
+	 *
 	 * @param ignoreEmptyRow 是否忽略空行
 	 * @return this
 	 */
@@ -148,7 +158,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 	/**
 	 * 设置单元格值处理逻辑<br>
 	 * 当Excel中的值并不能满足我们的读取要求时,通过传入一个编辑接口,可以对单元格值自定义,例如对数字和日期类型值转换为字符串等
-	 * 
+	 *
 	 * @param cellEditor 单元格值处理接口
 	 * @return this
 	 */
@@ -159,7 +169,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 获得标题行的别名Map
-	 * 
+	 *
 	 * @return 别名Map
 	 */
 	public Map<String, String> getHeaderAlias() {
@@ -168,7 +178,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 设置标题行的别名Map
-	 * 
+	 *
 	 * @param headerAlias 别名Map
 	 * @return this
 	 */
@@ -179,9 +189,9 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 增加标题别名
-	 * 
+	 *
 	 * @param header 标题
-	 * @param alias 别名
+	 * @param alias  别名
 	 * @return this
 	 */
 	public ExcelReader addHeaderAlias(String header, String alias) {
@@ -191,7 +201,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 去除标题别名
-	 * 
+	 *
 	 * @param header 标题
 	 * @return this
 	 */
@@ -203,7 +213,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 读取工作簿中指定的Sheet的所有行列数据
-	 * 
+	 *
 	 * @return 行的集合,一行使用List表示
 	 */
 	public List<List<Object>> read() {
@@ -212,7 +222,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 读取工作簿中指定的Sheet
-	 * 
+	 *
 	 * @param startRowIndex 起始行(包含,从0开始计数)
 	 * @return 行的集合,一行使用List表示
 	 * @since 4.0.0
@@ -223,12 +233,12 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 读取工作簿中指定的Sheet
-	 * 
+	 *
 	 * @param startRowIndex 起始行(包含,从0开始计数)
-	 * @param endRowIndex 结束行(包含,从0开始计数)
+	 * @param endRowIndex   结束行(包含,从0开始计数)
 	 * @return 行的集合,一行使用List表示
 	 */
-	@SuppressWarnings({ "rawtypes", "unchecked" })
+	@SuppressWarnings({"rawtypes", "unchecked"})
 	public List<List<Object>> read(int startRowIndex, int endRowIndex) {
 		checkNotClosed();
 		List<List<Object>> resultList = new ArrayList<>();
@@ -256,9 +266,48 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 	}
 
 	/**
+	 * 读取工作簿中指定的Sheet,此方法为类流处理方式,当读到指定单元格时,会调用CellEditor接口<br>
+	 * 用户通过实现此接口,可以更加灵活的处理每个单元格的数据。
+	 *
+	 * @param cellHandler    单元格处理器,用于处理读到的单元格及其数据
+	 * @since 5.3.8
+	 */
+	public void read(CellHandler cellHandler) {
+		read(0, Integer.MAX_VALUE, cellHandler);
+	}
+
+	/**
+	 * 读取工作簿中指定的Sheet,此方法为类流处理方式,当读到指定单元格时,会调用CellEditor接口<br>
+	 * 用户通过实现此接口,可以更加灵活的处理每个单元格的数据。
+	 *
+	 * @param startRowIndex 起始行(包含,从0开始计数)
+	 * @param endRowIndex   结束行(包含,从0开始计数)
+	 * @param cellHandler    单元格处理器,用于处理读到的单元格及其数据
+	 * @since 5.3.8
+	 */
+	public void read(int startRowIndex, int endRowIndex, CellHandler cellHandler) {
+		checkNotClosed();
+
+		startRowIndex = Math.max(startRowIndex, this.sheet.getFirstRowNum());// 读取起始行(包含)
+		endRowIndex = Math.min(endRowIndex, this.sheet.getLastRowNum());// 读取结束行(包含)
+
+		Row row;
+		short columnSize;
+		for (int y = startRowIndex; y <= endRowIndex; y++) {
+			row = this.sheet.getRow(y);
+			columnSize = row.getLastCellNum();
+			Cell cell;
+			for (short x = 0; x < columnSize; x++) {
+				cell = row.getCell(x);
+				cellHandler.handle(cell, CellUtil.getCellValue(cell));
+			}
+		}
+	}
+
+	/**
 	 * 读取Excel为Map的列表,读取所有行,默认第一行做为标题,数据从第二行开始<br>
 	 * Map表示一行,标题为key,单元格内容为value
-	 * 
+	 *
 	 * @return Map的列表
 	 */
 	public List<Map<String, Object>> readAll() {
@@ -268,10 +317,10 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 	/**
 	 * 读取Excel为Map的列表<br>
 	 * Map表示一行,标题为key,单元格内容为value
-	 * 
+	 *
 	 * @param headerRowIndex 标题所在行,如果标题行在读取的内容行中间,这行做为数据将忽略
-	 * @param startRowIndex 起始行(包含,从0开始计数)
-	 * @param endRowIndex 读取结束行(包含,从0开始计数)
+	 * @param startRowIndex  起始行(包含,从0开始计数)
+	 * @param endRowIndex    读取结束行(包含,从0开始计数)
 	 * @return Map的列表
 	 */
 	public List<Map<String, Object>> read(int headerRowIndex, int startRowIndex, int endRowIndex) {
@@ -306,8 +355,8 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 读取Excel为Bean的列表,读取所有行,默认第一行做为标题,数据从第二行开始
-	 * 
-	 * @param <T> Bean类型
+	 *
+	 * @param <T>      Bean类型
 	 * @param beanType 每行对应Bean的类型
 	 * @return Map的列表
 	 */
@@ -317,11 +366,11 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 读取Excel为Bean的列表
-	 * 
-	 * @param <T> Bean类型
+	 *
+	 * @param <T>            Bean类型
 	 * @param headerRowIndex 标题所在行,如果标题行在读取的内容行中间,这行做为数据将忽略,,从0开始计数
-	 * @param startRowIndex 起始行(包含,从0开始计数)
-	 * @param beanType 每行对应Bean的类型
+	 * @param startRowIndex  起始行(包含,从0开始计数)
+	 * @param beanType       每行对应Bean的类型
 	 * @return Map的列表
 	 * @since 4.0.1
 	 */
@@ -331,12 +380,12 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 读取Excel为Bean的列表
-	 * 
-	 * @param <T> Bean类型
+	 *
+	 * @param <T>            Bean类型
 	 * @param headerRowIndex 标题所在行,如果标题行在读取的内容行中间,这行做为数据将忽略,,从0开始计数
-	 * @param startRowIndex 起始行(包含,从0开始计数)
-	 * @param endRowIndex 读取结束行(包含,从0开始计数)
-	 * @param beanType 每行对应Bean的类型
+	 * @param startRowIndex  起始行(包含,从0开始计数)
+	 * @param endRowIndex    读取结束行(包含,从0开始计数)
+	 * @param beanType       每行对应Bean的类型
 	 * @return Map的列表
 	 */
 	@SuppressWarnings("unchecked")
@@ -357,7 +406,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 	/**
 	 * 读取为文本格式<br>
 	 * 使用{@link ExcelExtractor} 提取Excel内容
-	 * 
+	 *
 	 * @param withSheetName 是否附带sheet名
 	 * @return Excel文本
 	 * @since 4.1.0
@@ -370,7 +419,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 获取 {@link ExcelExtractor} 对象
-	 * 
+	 *
 	 * @return {@link ExcelExtractor}
 	 * @since 4.1.0
 	 */
@@ -387,7 +436,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 读取某一行数据
-	 * 
+	 *
 	 * @param rowIndex 行号,从0开始
 	 * @return 一行数据
 	 * @since 4.0.3
@@ -398,7 +447,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 读取某个单元格的值
-	 * 
+	 *
 	 * @param x X坐标,从0计数,即列号
 	 * @param y Y坐标,从0计数,即行号
 	 * @return 值,如果单元格无值返回null
@@ -411,7 +460,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 	/**
 	 * 获取Excel写出器<br>
 	 * 在读取Excel并做一定编辑后,获取写出器写出
-	 * 
+	 *
 	 * @return {@link ExcelWriter}
 	 * @since 4.0.6
 	 */
@@ -420,9 +469,10 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 	}
 
 	// ------------------------------------------------------------------------------------------------------- Private methods start
+
 	/**
 	 * 读取一行
-	 * 
+	 *
 	 * @param row 行
 	 * @return 单元格值列表
 	 */
@@ -432,7 +482,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 
 	/**
 	 * 转换标题别名,如果没有别名则使用原标题,当标题为空时,列号对应的字母便是header
-	 * 
+	 *
 	 * @param headerList 原标题列表
 	 * @return 转换别名列表
 	 */
@@ -443,25 +493,25 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
 			return result;
 		}
 
-		for(int i = 0; i < size; i++) {
+		for (int i = 0; i < size; i++) {
 			result.add(aliasHeader(headerList.get(i), i));
 		}
 		return result;
 	}
-	
+
 	/**
 	 * 转换标题别名,如果没有别名则使用原标题,当标题为空时,列号对应的字母便是header
-	 * 
+	 *
 	 * @param headerObj 原标题
-	 * @param index 标题所在列号,当标题为空时,列号对应的字母便是header
+	 * @param index     标题所在列号,当标题为空时,列号对应的字母便是header
 	 * @return 转换别名列表
 	 * @since 4.3.2
 	 */
 	private String aliasHeader(Object headerObj, int index) {
-		if(null == headerObj) {
+		if (null == headerObj) {
 			return ExcelUtil.indexToColName(index);
 		}
-		
+
 		final String header = headerObj.toString();
 		return ObjectUtil.defaultIfNull(this.headerAlias.get(header), header);
 	}

+ 5 - 2
hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellEditor.java

@@ -4,13 +4,16 @@ import org.apache.poi.ss.usermodel.Cell;
 
 /**
  * 单元格编辑器接口
- * @author Looly
  *
+ * @author Looly
  */
+@FunctionalInterface
 public interface CellEditor {
+
 	/**
 	 * 编辑
-	 * @param cell 单元格对象,可以获取单元格行、列样式等信息
+	 *
+	 * @param cell  单元格对象,可以获取单元格行、列样式等信息
 	 * @param value 单元格值
 	 * @return 编辑后的对象
 	 */

+ 20 - 0
hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellHandler.java

@@ -0,0 +1,20 @@
+package cn.hutool.poi.excel.cell;
+
+import org.apache.poi.ss.usermodel.Cell;
+
+/**
+ * 单元格处理器接口
+ *
+ * @author Looly
+ */
+@FunctionalInterface
+public interface CellHandler {
+
+	/**
+	 * 处理
+	 *
+	 * @param cell  单元格对象,可以获取单元格行、列样式等信息
+	 * @param value 单元格值
+	 */
+	void handle(Cell cell, Object value);
+}

+ 6 - 0
hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelReadTest.java

@@ -208,4 +208,10 @@ public class ExcelReadTest {
 		Assert.assertEquals(11L, read.get(2).get(2));
 	}
 
+	@Test
+	public void readCellsTest() {
+		final ExcelReader reader = ExcelUtil.getReader("merge_test.xlsx");
+		reader.read((cell, value)-> Console.log("{}, {} {}", cell.getRowIndex(), cell.getColumnIndex(), value));
+	}
+
 }