You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java中用Apache POI-3.17读取未保存的实时更新Excel值

解决方案:通过COM自动化读取运行中Excel的实时数据

首先得明确:Apache POI 3.17本身是针对磁盘上的静态Excel文件进行读写的,而Nest Trader实时更新的是运行中Excel进程内存里的单元格数据——这些数据还没保存到磁盘,甚至Excel会独占锁定文件,导致POI根本无法读取到最新内容。所以我们得换个思路,直接从Excel的内存实例中读取数据,而不是读磁盘文件。

这里推荐用JACOB(Java-COM Bridge)实现Java和Windows COM接口的交互,直接调用Excel的ActiveX对象来获取实时数据。

步骤1:引入依赖

先给项目添加JACOB的依赖(Maven示例):

<dependency>
    <groupId>net.sf.jacob-project</groupId>
    <artifactId>jacob</artifactId>
    <version>1.18</version>
</dependency>

注意:JACOB需要对应系统位数的dll文件(jacob-1.18-x86.dll或jacob-1.18-x64.dll),要把它放到JRE/bin目录下,或者通过VM参数指定路径。

步骤2:编写核心代码

下面是完整示例,实现毫秒级读取Excel实时值并存入数据库:

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
import java.util.Timer;
import java.util.TimerTask;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class ExcelRealTimeReader {
    private ActiveXComponent excelApp;
    private Dispatch targetWorkbook;
    private Dispatch targetSheet;

    // 初始化:找到Nest Trader对应的Excel工作簿
    public void init(String workbookName) {
        try {
            // 获取已运行的Excel实例
            excelApp = new ActiveXComponent("Excel.Application");
            excelApp.setProperty("Visible", new Variant(false)); // 无需显示Excel窗口

            // 遍历所有打开的工作簿
            Dispatch workbooks = excelApp.getProperty("Workbooks").toDispatch();
            int workbookCount = Dispatch.call(workbooks, "Count").getInt();

            for (int i = 1; i <= workbookCount; i++) {
                Dispatch workbook = Dispatch.call(workbooks, "Item", new Variant(i)).toDispatch();
                String name = Dispatch.call(workbook, "Name").getString();
                if (name.equals(workbookName)) {
                    targetWorkbook = workbook;
                    // 替换为你需要读取的工作表(这里取第一个)
                    targetSheet = Dispatch.call(targetWorkbook, "Sheets", new Variant(1)).toDispatch();
                    break;
                }
            }

            if (targetWorkbook == null) {
                throw new RuntimeException("未找到目标工作簿:" + workbookName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 读取指定单元格的实时值(Excel行列从1开始计数)
    private String getCellValue(int row, int col) {
        if (targetSheet == null) return null;
        Dispatch cell = Dispatch.call(targetSheet, "Cells", new Variant(row), new Variant(col)).toDispatch();
        return Dispatch.call(cell, "Value").getString();
    }

    // 启动定时读取任务(毫秒级频率)
    public void startReading(int intervalMs, String dbUrl, String dbUser, String dbPwd) {
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                try {
                    // 替换为你需要读取的单元格位置
                    String latestPrice = getCellValue(1, 1);
                    String latestVolume = getCellValue(1, 2);

                    if (latestPrice != null && latestVolume != null) {
                        saveToDatabase(latestPrice, latestVolume, dbUrl, dbUser, dbPwd);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, 0, intervalMs);
    }

    // 数据库存储方法
    private void saveToDatabase(String price, String volume, String dbUrl, String dbUser, String dbPwd) {
        String sql = "INSERT INTO stock_real_time_data (price, volume, update_time) VALUES (?, ?, NOW())";
        try (Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPwd);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, price);
            pstmt.setString(2, volume);
            pstmt.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 释放资源,避免Excel进程残留
    public void destroy() {
        if (targetWorkbook != null) {
            Dispatch.call(targetWorkbook, "Close", new Variant(false)); // 不保存关闭
        }
        if (excelApp != null) {
            excelApp.invoke("Quit", new Variant[0]);
            excelApp.safeRelease();
        }
    }

    public static void main(String[] args) {
        ExcelRealTimeReader reader = new ExcelRealTimeReader();
        try {
            // 替换为你的Nest Trader输出工作簿名称
            reader.init("StockOutput.xlsx");
            // 每100毫秒读取一次,替换为你的数据库连接信息
            reader.startReading(100, "jdbc:mysql://localhost:3306/stock_db", "root", "your_password");
        } catch (Exception e) {
            e.printStackTrace();
            reader.destroy();
        }
    }
}

关键注意事项

  • 运行环境限制:这个方案只能在Windows系统上运行,因为依赖Windows的COM技术。
  • Excel状态:必须确保Nest Trader对应的Excel文件处于打开状态,且没有被其他进程锁定。
  • 性能优化:如果毫秒级更新频率很高,建议改成批量插入(比如攒10条数据再一次性插入),避免频繁数据库操作拖慢性能。
  • 异常处理:要处理Excel被意外关闭的情况,比如在定时任务中检测targetWorkbook是否为空,为空则重新初始化获取实例。
  • 资源释放:程序结束时一定要调用destroy()方法,否则Excel进程会残留占用系统资源。

内容的提问来源于stack exchange,提问作者CH.Rajshekhar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:00:39