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

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

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

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

1. 添加 Maven 依赖
XML 复制代码
<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. 完整代码实现
java 复制代码
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、不同表头等),可以进一步扩展此代码。

相关推荐
2501_924890526 分钟前
商超场景徘徊识别误报率↓79%!陌讯多模态时序融合算法落地优化
java·大数据·人工智能·深度学习·算法·目标检测·计算机视觉
鱼鱼说测试40 分钟前
postman接口自动化测试
开发语言·lua
從南走到北1 小时前
JAVA国际版东郊到家同城按摩服务美容美发私教到店服务系统源码支持Android+IOS+H5
android·java·开发语言·ios·微信·微信小程序·小程序
_不会dp不改名_1 小时前
C++ 20: Concepts 与Requires
开发语言·c++20
qianmoq1 小时前
第04章:数字流专题:IntStream让数学计算更简单
java
韭菜钟2 小时前
Qt从qmake迁移到cmake的记录
开发语言·qt
少陵野小Tommy2 小时前
Python能用古诗词数据库做什么7:根据标题、诗句查找诗歌
开发语言·数据库·python
带只拖鞋去流浪2 小时前
Java集合(Collection、Map、转换)
java
超级小忍2 小时前
使用 GraalVM Native Image 将 Spring Boot 应用编译为跨平台原生镜像:完整指南
java·spring boot·后端
野犬寒鸦2 小时前
力扣hot100:搜索二维矩阵与在排序数组中查找元素的第一个和最后一个位置(74,34)
java·数据结构·算法·leetcode·list