@@ -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 < > ( ) ;
@@ -255,10 +265,49 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
return resultList ;
}
/**
* 读取工作簿中指定的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 ) ;
}