Java 实现 Excel 文件对比与数据填充

发布于:2025-07-10 ⋅ 阅读:(22) ⋅ 点赞:(0)

        新老数据的维护工具,例如:A文件有a、b、c列共十条数据,B文件有a、b、c、d列数据共15条数据(其中有包含A的一些数据)如何快速的将A里有的数据放入到B中(长点心吧!可别一条条比对着录入数据)

下面是一个完整的 Java 实现,

        使用 Apache POI 库处理 Excel 文件,对比 A、B 文件中的"测点标识"列(定位到相同的数据行),并将 A 文件中的"标签值"列填充到 B 文件对应的位置。

1. 添加 Maven 依赖
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.2.3</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
</dependency>
2. 完整代码实现
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;

public class ExcelDataComparator {

    public static void main(String[] args) {
        String fileAPath = "path/to/FileA.xlsx";
        String fileBPath = "path/to/FileB.xlsx";
        String outputPath = "path/to/OutputFile.xlsx";

        try {
            // 1. 读取文件A的数据(测点标识 -> 标签值)
            Map<String, String> pointToTagMap = readFileA(fileAPath);

            // 2. 处理文件B并填充数据
            processFileB(fileBPath, outputPath, pointToTagMap);

            System.out.println("数据处理完成!输出文件: " + outputPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取文件A,构建测点标识到标签值的映射
     */
    private static Map<String, String> readFileA(String filePath) throws Exception {
        Map<String, String> map = new HashMap<>();
        FileInputStream fis = new FileInputStream(filePath);
        Workbook workbook = new XSSFWorkbook(fis);
        Sheet sheet = workbook.getSheetAt(0); // 假设使用第一个工作表

        // 获取表头行确定列索引
        Row headerRow = sheet.getRow(0);
        int pointIdIndex = -1;
        int tagValueIndex = -1;

        for (Cell cell : headerRow) {
            String headerName = cell.getStringCellValue().trim();
            if ("测点标识".equals(headerName)) {
                pointIdIndex = cell.getColumnIndex();
            } else if ("标签值".equals(headerName)) {
                tagValueIndex = cell.getColumnIndex();
            }
        }

        if (pointIdIndex == -1 || tagValueIndex == -1) {
            throw new RuntimeException("文件A中缺少必要的表头列");
        }

        // 遍历数据行
        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row == null) continue;

            String pointId = getCellStringValue(row.getCell(pointIdIndex));
            String tagValue = getCellStringValue(row.getCell(tagValueIndex));

            if (pointId != null && !pointId.isEmpty()) {
                map.put(pointId, tagValue);
            }
        }

        workbook.close();
        fis.close();
        return map;
    }

    /**
     * 处理文件B并填充数据
     */
    private static void processFileB(String inputPath, String outputPath, 
                                   Map<String, String> pointToTagMap) throws Exception {
        FileInputStream fis = new FileInputStream(inputPath);
        Workbook workbook = new XSSFWorkbook(fis);
        Sheet sheet = workbook.getSheetAt(0);

        // 获取表头行确定列索引
        Row headerRow = sheet.getRow(0);
        int pointIdIndex = -1;
        int tagValueIndex = -1;

        for (Cell cell : headerRow) {
            String headerName = cell.getStringCellValue().trim();
            if ("测点标识".equals(headerName)) {
                pointIdIndex = cell.getColumnIndex();
            } else if ("标签值".equals(headerName)) {
                tagValueIndex = cell.getColumnIndex();
            }
        }

        if (pointIdIndex == -1) {
            throw new RuntimeException("文件B中缺少'测点标识'列");
        }

        // 如果文件B没有"标签值"列,可以创建(这里假设已有该列)
        if (tagValueIndex == -1) {
            tagValueIndex = headerRow.getLastCellNum();
            Cell newHeaderCell = headerRow.createCell(tagValueIndex);
            newHeaderCell.setCellValue("标签值");
        }

        // 遍历数据行并填充
        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row == null) continue;

            String pointId = getCellStringValue(row.getCell(pointIdIndex));
            if (pointId == null || pointId.isEmpty()) continue;

            // 从文件A的映射中获取对应的标签值
            String tagValue = pointToTagMap.get(pointId);
            if (tagValue != null) {
                Cell targetCell = row.getCell(tagValueIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                targetCell.setCellValue(tagValue);
            }
        }

        // 保存修改后的文件
        FileOutputStream fos = new FileOutputStream(outputPath);
        workbook.write(fos);
        workbook.close();
        fos.close();
    }

    /**
     * 安全获取单元格字符串值
     */
    private static String getCellStringValue(Cell cell) {
        if (cell == null) return "";

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue().trim();
            case NUMERIC:
                return String.valueOf((int) cell.getNumericCellValue());
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }
}

关键点说明

  1. 数据结构

    • 使用 Map<String, String> 存储文件A中的"测点标识"->"标签值"映射关系

  2. 列索引定位

    • 动态查找"测点标识"和"标签值"所在的列索引

  3. 单元格处理

    • getCellStringValue() 方法处理各种类型的单元格数据

    • 使用 Row.MissingCellPolicy.CREATE_NULL_AS_BLANK 处理可能为空的单元格

  4. 文件处理

    • 读取文件A构建映射关系

    • 读取文件B并修改数据

    • 输出到新文件(避免修改原始文件)

使用示例

假设:

  • 文件A.xlsx:

    测点标识 标签值
    P001 温度
    P002 压力
  • 文件B.xlsx:

    测点标识 其他数据 标签值
    P001 xxx
    P003 yyy

运行程序后,输出文件将变为:

测点标识 其他数据 标签值
P001 xxx 温度
P003 yyy

注意事项

  1. 文件格式支持:代码使用 .xlsx 格式(POI的XSSF)

  2. 性能优化:对于大文件,可以考虑使用 SXSSFWorkbook

  3. 错误处理:实际应用中应添加更完善的异常处理

  4. 表头检查:确保两个文件都有"测点标识"列

如果需要处理更复杂的情况(如多sheet、不同表头等),可以进一步扩展此代码。


网站公告

今日签到

点亮在社区的每一天
去签到