JAVA 读取Excel(支持xlsx、xls格式, 支持合并单元格)

记录一下最近使用java操作excel的代码。

  1. 导包。注意两者版本需要一致

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.9</version>
    </dependency>
    <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.9</version>
    </dependency>
  2. 解析excel代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    public class ExcelDemo {

    public static void main(String[] args) {
    // 获取输入流
    InputStream in = getResourcesFileInputStream("Test.xlsx");
    //InputStream in = getResourcesFileInputStream("Test.xls");

    // 解析---1
    // 解析Excel所有sheet,所有行,所有列
    List<List<String[]>> allData = ExcelUtil.read(in);

    // 解析---2
    // 解析第一个sheet数据
    ExcelUtil.readSheet(in, 0, sheet -> {
    //解析第3行到最后一行,第2列到第9列的数据
    List<String[]> source = ExcelUtil.readSheetPart(sheet, 2, sheet.getLastRowNum(), 1, 8);
    });

    // 解析---3
    // 完全自定义解析
    ExcelUtil.readByCustomize(in, wb -> {
    // doSomeThing()...可参照ExcelUtil.readExcel()方法
    });

    in.close();
    }

    /**
    * 加载Resources目录下的文件
    * @param fileName 文件名
    * @return
    */
    public static InputStream getResourcesFileInputStream(String fileName){
    // Resources目录的绝对路径
    // String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
    InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName);
    return in;
    }
    }

注意事项获取的excel行数不正确解决方法

  1. Excel工具类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    import org.apache.commons.lang3.StringUtils;
    import org.apache.poi.ss.usermodel.Cell;
    import org.apache.poi.ss.usermodel.WorkbookFactory;
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    import org.apache.poi.ss.usermodel.*;
    import org.apache.poi.ss.util.CellRangeAddress;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    import java.io.IOException;
    import java.io.InputStream;
    import java.util.*;

    /**
    * Excel工具类
    */
    public class ExcelUtil {

    private static Logger logger = LoggerFactory.getLogger(ExcelUtil.class);

    /**
    * 对excel单个sheet进行处理的接口
    */
    public interface SheetHandler {
    /**
    * 对sheet进行处理
    * @param sheet
    */
    void handle(Sheet sheet);
    }

    /**
    * 对excel进行处理的接口
    */
    public interface WorkBookHandler {
    /**
    * 对excel进行处理
    * @param wb
    * @return
    */
    void handle(Workbook wb);
    }

    /**
    * 读取excel指定sheet数据<br>未关闭io
    * @param in
    */
    public static void readSheet(InputStream in, int sheetIdx, SheetHandler handler) throws IOException, InvalidFormatException {
    // 创建工作簿
    Workbook wb = createWorkBook(in);
    // 接口回调处理
    handler.handle(getSheetByIdx(wb, sheetIdx));
    }


    /**
    * 读取excel全部sheet全部行数据<br>未关闭io
    * @param in
    * @return List<List<String[]>> <br>List<String[]>表示第i个sheet<br> String[]表示sheet某行
    */
    public static List<List<String[]>> read(InputStream in) throws IOException, InvalidFormatException {
    // 创建工作簿
    Workbook wb = createWorkBook(in);
    // 默认读取所有行,所有列
    return readExcel(wb);
    }

    /**
    * 读取excel<br>自定义解析方式<br>未关闭io
    * @param in
    * @return
    */
    public static void readByCustomize(InputStream in, WorkBookHandler handler) throws IOException, InvalidFormatException {
    // 创建工作簿
    Workbook wb = createWorkBook(in);

    handler.handle(wb);
    }

    /**
    * 读取指定sheet的范围行,范围列
    * @param sheet excel 某个sheet
    * @param startRow 开始行下标
    * @param endRow 结束行下标
    * @param startCol 开始列下标
    * @param endCol 结束列下标
    * @return 指定范围的数据。一个String[]是一行数据
    */
    public static List<String[]> readSheetPart(Sheet sheet, int startRow, int endRow, int startCol, int endCol){

    if(sheet == null){
    logger.warn("excel sheet is not exist");
    return null;
    }

    int firstRow = sheet.getFirstRowNum();
    int lastRow = sheet.getLastRowNum();
    logger.info("sheet firstRow:"+firstRow);
    logger.info("sheet lastRow:"+lastRow);
    if(startRow < 0 || startRow > lastRow || startRow > endRow){
    return null;
    }
    if(endRow > lastRow){
    return null;
    }

    List<String[]> list = new ArrayList<>();
    // 逐行解析
    for (int i = startRow; i <= endRow ; i++) {
    Row row = sheet.getRow(i);
    // 过滤空行
    if(row == null){
    continue;
    }
    int firstCol = row.getFirstCellNum();
    int lastCol = row.getLastCellNum();
    logger.info("row("+i+") firstCol:"+firstCol);
    logger.info("row("+i+") lastCol:"+lastCol);
    if(startCol < 0 || startCol > lastCol || startCol > endCol){
    return null;
    }
    if(endCol > lastCol){
    return null;
    }

    int colIdx = 0;
    int objIdx = 0;
    String[] objs = new String[endCol-startCol+1];
    // 逐列解析
    for (Cell c : row) {
    // 读取指定列数据
    if(colIdx >= startCol && colIdx <= endCol){
    c.setCellType(Cell.CELL_TYPE_STRING);
    boolean isMerge = isMergedRegion(sheet, i, c.getColumnIndex());
    String data = "";
    //判断是否具有合并单元格
    if(isMerge) {
    data = getMergedRegionValue(sheet, row.getRowNum(), c.getColumnIndex());
    }else {
    data = c.getRichStringCellValue().toString();
    }
    objs[objIdx++]=data;
    }
    colIdx++;
    }
    list.add(objs);
    }

    if(list.size() == 0){
    logger.warn("excel sheet data is space");
    }

    return list;
    }

    /**
    * 读取excel文件
    * @param wb
    * @return List<List<String[]>> <br>List<String[]>表示第i个sheet<br> String[]表示sheet某行
    */
    public static List<List<String[]>> readExcel(Workbook wb) {

    // 总sheet数
    int sheetNum = wb.getNumberOfSheets();
    logger.info("excel sheetNum is :"+sheetNum);

    // 遍历sheet
    List<List<String[]>> list = new ArrayList<>();
    for (int i = 0; i < sheetNum ; i++) {
    Sheet sheet = wb.getSheetAt(i);
    List<String[]> sheetData = readOneSheet(sheet);
    list.addAll(Collections.singleton(sheetData));
    }

    return list;
    }

    /**
    * 读取单个sheet数据,封装为List<String[]><br>
    * @warn 可能会有全是空串的数据
    * @return List<String[]>,一个String[]是
    */
    public static List<String[]> readOneSheet(Sheet sheet){
    int startRow = sheet.getFirstRowNum();
    int endRow = sheet.getLastRowNum();
    logger.info("sheet startRow:"+startRow);
    logger.info("sheet endRow:"+endRow);
    List<String[]> list = new ArrayList<>();
    // 遍历行
    for (int i = startRow; i <= endRow ; i++) {
    Row row = sheet.getRow(i);
    if(row == null){
    continue;
    }
    // int startColIdx = row.getFirstCellNum();
    int endColIdx = row.getLastCellNum();
    String[] objs = new String[endColIdx+1];
    int colIdx = 0;
    // 遍历列
    for (Cell c : row) {
    c.setCellType(Cell.CELL_TYPE_STRING);
    String data = "";
    boolean isMerge = isMergedRegion(sheet, i, c.getColumnIndex());
    //判断是否具有合并单元格
    if(isMerge) {
    data = getMergedRegionValue(sheet, row.getRowNum(), c.getColumnIndex());
    }else {
    data = c.getRichStringCellValue().toString();
    }
    objs[colIdx]=data;
    colIdx++;
    }
    list.add(objs);
    }

    if(list.size() == 0){
    logger.warn("excel sheet data is space");
    }

    return list;
    }

    /**
    * 获取合并单元格的值<br>
    * 即获取合并单元格第一个cell的值
    * @param sheet
    * @param row
    * @param column
    * @return
    */
    public static String getMergedRegionValue(Sheet sheet ,int row , int column){

    // 获得一个 sheet 中合并单元格的数量
    int sheetMergeCount = sheet.getNumMergedRegions();

    // 遍历合并单元格
    for(int i = 0 ; i < sheetMergeCount ; i++){

    // 得出具体的合并单元格
    CellRangeAddress ca = sheet.getMergedRegion(i);

    // 得到合并单元格的起始行, 结束行, 起始列, 结束列
    int firstColumn = ca.getFirstColumn();
    int lastColumn = ca.getLastColumn();
    int firstRow = ca.getFirstRow();
    int lastRow = ca.getLastRow();

    // 获取合并单元格第一个cell的值
    if(row >= firstRow && row <= lastRow){
    if(column >= firstColumn && column <= lastColumn){
    Row fRow = sheet.getRow(firstRow);
    Cell fCell = fRow.getCell(firstColumn);
    return getCellValue(fCell) ;
    }
    }
    }

    return null ;
    }

    /**
    * 判断指定的单元格是否是合并单元格
    * @param sheet
    * @param row 行下标
    * @param column 列下标
    * @return
    */
    public static boolean isMergedRegion(Sheet sheet,int row ,int column) {

    // 得到一个sheet中有多少个合并单元格
    int sheetMergeCount = sheet.getNumMergedRegions();
    for (int i = 0; i < sheetMergeCount; i++) {

    // 得出具体的合并单元格
    CellRangeAddress range = sheet.getMergedRegion(i);

    // 得到合并单元格的起始行, 结束行, 起始列, 结束列
    int firstColumn = range.getFirstColumn();
    int lastColumn = range.getLastColumn();
    int firstRow = range.getFirstRow();
    int lastRow = range.getLastRow();

    // 判断该单元格是否在合并单元格范围之内, 如果是, 则返回 true
    if(row >= firstRow && row <= lastRow){
    if(column >= firstColumn && column <= lastColumn){
    return true;
    }
    }
    }
    return false;
    }

    /**
    * 判断sheet页中是否含有合并单元格
    * @param sheet
    * @return
    */
    public static boolean hasMerged(Sheet sheet) {
    return sheet.getNumMergedRegions() > 0 ? true : false;
    }

    /**
    * 获取单元格的值
    * @param cell
    * @return
    */
    public static String getCellValue(Cell cell){
    if(cell == null) return "";
    switch (cell.getCellType()){
    case Cell.CELL_TYPE_STRING:
    return cell.getStringCellValue();
    case Cell.CELL_TYPE_BOOLEAN:
    return String.valueOf(cell.getBooleanCellValue());
    case Cell.CELL_TYPE_FORMULA:
    return cell.getCellFormula() ;
    case Cell.CELL_TYPE_NUMERIC:
    return String.valueOf(cell.getNumericCellValue());
    default:
    return "";
    }
    }

    /**
    * 创建工作簿
    * @param in
    */
    private static Workbook createWorkBook(InputStream in) throws IOException, InvalidFormatException {
    Workbook wb = WorkbookFactory.create(in);
    return wb;
    }

    /**
    * 获取sheet
    * @param wb
    * @param sheetIdx
    */
    public static Sheet getSheetByIdx(Workbook wb, int sheetIdx){

    // 总sheet数
    int sheetNum = wb.getNumberOfSheets();

    // sheet不存在
    if(sheetIdx < 0 || sheetIdx >= sheetNum){
    return null;
    }

    // 获取sheet
    Sheet sheet = wb.getSheetAt(sheetIdx);

    return sheet;
    }


    /*----------写excel相关----------*/
    /**
    * 添加合并单元格
    * @param sheet
    * @param firstRow 开始行
    * @param lastRow 结束行
    * @param firstCol 开始列
    * @param lastCol 结束列
    */
    public static void mergeRegion(Sheet sheet, int firstRow, int lastRow, int firstCol, int lastCol) {
    sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol));
    }
    }
------------- 本文结束  感谢您的阅读 -------------
评论