EasyExcel中的数据第一行获取问题

EasyExcel中的数据第一行获取问题及解决方案详解

在使用Java开发中,处理Excel文件是一个常见需求。EasyExcel作为一个流行的Excel操作库,提供了方便而高效的API来读写Excel文件。然而,有时会遇到数据第一行被误读为表头的问题,特别是在Excel文件的第一行不是标准表头而是实际数据时,这一问题显得尤为突出。
本文将详细讨论这一问题的根本原因,并提供一种有效的解决方案。

EasyExcel简介 EasyExcel是阿里巴巴开源的一款Java操作Excel的工具库,它提供了强大的功能,支持大数据量的读写操作,并且提供了丰富的样式和格式处理功能,适用于各种场景下的Excel文件处理需求。

问题描述

在使用EasyExcel读取Excel文件时,经常会出现第一行数据被错误地识别为表头的情况。这一问题的根本原因在于EasyExcel在某些情况下无法正确识别Excel文件中数据行和表头行的区分,特别是当Excel文件结构比较复杂或者存在特定格式时,EasyExcel的默认解析逻辑可能会出现偏差。

解决方案详解

为了解决数据第一行获取问题,我们可以采取以下步骤来调整和优化EasyExcel的读取操作,确保能够正确获取实际数据行而非表头行:

方案1:

1. 手动指定数据起始行 在读取Excel文件时,手动指定数据的起始行,而不依赖EasyExcel的自动识别。这可以通过设置headRowNumber来实现,明确告知EasyExcel从第几行开始读取数据。

ExcelReaderBuilder readBuilder = EasyExcel.read(inputStream, ExcelData.class, new ExcelDataListener()); 
readBuilder.sheet().headRowNumber(2); // 指定从第3行开始读取数据 
readBuilder.doRead();

在上述代码中,通过headRowNumber(2)指定从第3行开始读取数据,避免将第一行误读为表头。

数据处理逻辑中排除表头行

在实际数据处理逻辑中,可以通过逻辑判断排除表头行,确保只处理实际的数据行。例如,在invoke方法中可以添加逻辑判断:

@Override 
public void invoke(ExcelData data, AnalysisContext context) {
 if (context.readRowHolder().getRowIndex() > 0) { // 跳过表头行 // 处理实际数据逻辑 } }

通过context.readRowHolder().getRowIndex() > 0判断当前行索引大于0时才处理数据,跳过表头行的处理。

使用后处理器进行二次处理

EasyExcel提供了后处理器(Handler)机制,在数据读取完成后可以进行二次处理。可以在doAfterAllAnalysed方法中对数据进行进一步处理或过滤,确保最终数据的准确性和完整性。

@Override 
public void doAfterAllAnalysed(AnalysisContext context) { 
// 数据处理完成后的逻辑 
processData(dataList);
}

在上述代码中,可以在doAfterAllAnalysed方法中调用processData方法,对数据进行进一步的处理或者存储操作。

示例代码
以下是一个完整的示例代码,展示了如何使用EasyExcel读取Excel文件并处理数据,同时避免数据第一行被误读为表头的问题:

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class ExcelReaderExample {

    public static void main(String[] args) {
        String fileName = "path/to/your/excel/file.xlsx";
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(fileName);
            ExcelReaderBuilder readBuilder = EasyExcel.read(inputStream, ExcelData.class, new ExcelDataListener());
            readBuilder.sheet().headRowNumber(2); // 指定从第3行开始读取数据
            readBuilder.doRead();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static class ExcelDataListener extends AnalysisEventListener<ExcelData> {

        private List<ExcelData> dataList = new ArrayList<>();

        @Override
        public void invoke(ExcelData data, AnalysisContext context) {
            if (context.readRowHolder().getRowIndex() > 0) { // 跳过表头行
                // 处理实际数据逻辑
                dataList.add(data);
            }
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            // 数据处理完成后的逻辑
            processData(dataList);
        }

        private void processData(List<ExcelData> dataList) {
            // 处理数据的具体逻辑
            for (ExcelData data : dataList) {
                System.out.println(data.toString());
            }
        }
    }

    public static class ExcelData {
        // Excel中的数据字段对应的Java属性
        private String column1;
        private String column2;
        
        // 省略getter和setter方法
    }
}

方案2:

第一行数据读在表头单独处理。


	@Override
    @SneakyThrows
    public byte[] exportExcel(List<String> sheet1Ids, List<String> sheet2Ids, List<String> sheet3Ids, String startDate, String endDate) {
        byte[] result;

        // 读取模版
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
             InputStream inputStream = templateFileService.getTemplateInputStreamByPath(dataComparisonFileResource.getPath())) {
            ExcelWriter excelWriter = EasyExcel.write(outputStream)
                    .withTemplate(inputStream)
                    .autoCloseStream(true)
                    .registerWriteHandler(new CustomSheet1CellWriteHandler())
                    .build();

            // 写入表1 数据
            List<LfDispatchDataComparisonGridOperationVo> sheet1Data = getGridOperationData(sheet1Ids, startDate, endDate);
            this.writerSheet1(excelWriter, sheet1Data);

            // 写入表2 数据
            List<LfDispatchDataComparisonGwEnergyVo> sheet2Data = getGwEnergyData(sheet2Ids, startDate, endDate);
            this.writerSheet2(excelWriter, sheet2Data);

            // 写入表3 数据
            List<LfDispatchDataComparisonNewEnergyOperationVo> sheet3Data = getNewEnergyOperationData(sheet3Ids, startDate, endDate);
            this.writerSheet3(excelWriter, sheet3Data);

            // 生成excel
            excelWriter.finish();

            // 确保所有内容都写入输出流中
            result = outputStream.toByteArray();
        }

        return result;
    }


    /**
     * 自定义sheet1的cell样式 用于标记 负荷占比、电量占比 大于1的单元格
     */
    public static class CustomSheet1CellWriteHandler implements WorkbookWriteHandler, CellWriteHandler {

        /**
         * 处理第一行数据 (easyExcel工具的bug 会将第一行数据读在表头)
         *
         * @param context 上下文
         */
        @Override
        public void afterCellDispose(CellWriteHandlerContext context) {
            if (context.getRowIndex() == 2 && (context.getColumnIndex() == 14 || context.getColumnIndex() == 15)) {
                // 处理第第一个sheet
                Sheet sheet = context.getRow().getSheet().getWorkbook().getSheetAt(0);
                Row row = sheet.getRow(2);

                Cell cell14 = row.getCell(14);
                Cell cell15 = row.getCell(15);

//                if (cell14 == null || cell15 == null){
//                    cell14 = row.createCell(14, CellType.STRING);
//                    cell15 = row.createCell(15, CellType.STRING);
//                }

                // 应用红色样式
                applyRedStyleToCells(cell14, cell15);
            }
        }

        /**
         * 处理除了第一行以外的其他数据行
         *
         * @param context 上下文
         */
        @Override
        public void afterWorkbookDispose(WorkbookWriteHandlerContext context) {
            Workbook workbook = context.getWriteWorkbookHolder().getWorkbook();
            // 只处理 sheet1
            Sheet sheet = workbook.getSheetAt(0);

            applyRedStyleToSheet(sheet);
        }

        /**
         * 按列标记红色
         *
         * @param sheet 工作表
         */
        private void applyRedStyleToSheet(Sheet sheet) {
            for (Row row : sheet) {
                applyRedStyleToCells(row.getCell(14), row.getCell(15));
            }
        }

        /**
         * 对指定的单元格应用红色字体样式
         *
         * @param cells 需要应用样式的单元格
         */
        private void applyRedStyleToCells(Cell... cells) {
            for (Cell cell : cells) {
                if (cell != null && cell.getCellType() == CellType.NUMERIC && cell.getNumericCellValue() > 1) {
                    Workbook workbook = cell.getSheet().getWorkbook();
                    CellStyle originalCellStyle = cell.getCellStyle();
                    CellStyle redCellStyle = workbook.createCellStyle();
                    redCellStyle.cloneStyleFrom(originalCellStyle);

                    // 创建一个红色字体
                    Font redFont = workbook.createFont();
                    redFont.setColor(IndexedColors.RED.getIndex());
                    redCellStyle.setFont(redFont);

                    cell.setCellStyle(redCellStyle);
                }
            }
        }
    }

总结
我总结:建议不再使用EasyExcel工具。

  • 10
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值