跳到主要内容

历史流式读

概述

IDE 趋势图拉历史时, 一次性把万点装进 List 会让 EDT 卡顿 + OOM。readHistoryStream 返回 Stream<DataValue>, 业务侧 forEach 拿一条处理一条。

对应规范段: Part 11 §6.5。

API

方法类别读写说明
ua.readHistoryStream(nodeId, t0, t1, batchSize)历史返回 Stream<DataValue>
参数默认说明
nodeId历史节点
startUtc起始 Instant
endUtc结束 Instant
batchSize1000每次 RPC 最多点数

代码示例

import com.darra.opcua.*;
import java.time.*;
import java.util.stream.Stream;

try (DarraOpcUa ua = new DarraOpcUa("opc.tcp://localhost:4840")) {
ua.connect();

Instant t1 = Instant.now();
Instant t0 = t1.minus(Duration.ofHours(24));

// 1) 边拉边渲染
try (Stream<DataValue> s = ua.readHistoryStream("ns=2;s=Temp", t0, t1, 1000)) {
s.forEach(dv -> {
try (dv) {
chartSeries.addPoint(dv.sourceTimestamp, dv.value.asDouble());
}
});
}

// 2) LINQ 风格筛选
long badCount;
try (Stream<DataValue> s = ua.readHistoryStream("ns=2;s=Temp", t0, t1, 1000)) {
badCount = s.filter(dv -> dv.status != StatusCode.Good)
.peek(DataValue::close)
.count();
}
System.out.println("24h 内 " + badCount + " 个坏值");
}

实现限制

  • 当前底层 readHistory 不暴露 ContinuationPoint, 一次 RPC 返回区间内所有点 (受 batchSize 限)
  • 大区间业务侧自行切片
  • 必须 close 每个 dv, 否则 native 内存泄漏

最佳实践

  • try-with-resources 包 Stream
  • 区间 > 1 小时建议外层切片
  • UI 渲染节流: 每 100 条 refresh

跨语言对照

C#PythonJavaC++RustC
ReadHistoryStreamAsyncread_history_streamreadHistoryStreamReadHistoryStreamAsyncread_history_streamDarraUa_Session_ReadHistoryStream

下一步