
本文介绍如何在 Spring 应用中高效读取分号分隔的 CSV 文件,提取 Timestamp、Code 和 State 字段,并基于预定义的状态流转规则(如 UN → ACK/RTNUN → NORM、UPR → NORM),精准计算合法状态变更的时间差(毫秒级)。
本文介绍如何在 spring 应用中高效读取分号分隔的 csv 文件,提取 timestamp、code 和 state 字段,并基于预define的状态流转规则(如 un → ack/rtnun → norm、upr → norm),精准计算合法状态变更的时间差(毫秒级)。
在 Java(尤其是 Spring 生态)中处理带业务语义的 CSV 数据时,硬编码字符串切分 + 多层嵌套 if 判断极易导致逻辑混乱、可维护性差。正确的做法是:分层解耦 —— 格式解析交由成熟库,状态流转建模为有限状态机(FSM),时间计算依托 Java 8+ 时间 API。以下为推荐实现方案。
✅ 1. 使用 Apache Commons CSV 安全解析 CSV
CSV 格式看似简单,但实际常含空字段、引号包裹、时区偏移(如 +0200)等边界情况。直接 String.split(";") 易出错。推荐引入 Apache Commons CSV(Maven):
<dependency><groupid>org.apache.commons</groupid><artifactid>commons-csv</artifactid><version>1.10.0</version></dependency>
解析示例(支持带标题行、分号分隔、自动 trim 空白):
public List<csvevent> parseCsv(Path csvPath) throws IOException {
try (Reader reader = Files.newBufferedReader(csvPath, StandardCharsets.UTF_8)) {
return CSVFormat.EXCEL
.withFirstRecordAsHeader()
.withIgnoreEmptyLines()
.withTrim()
.withDelimiter(';') // 关键:指定分号分隔符
.parse(reader)
.getRecords()
.stream()
.map(this::toCsvEvent)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}
private CsvEvent toCsvEvent(CSVRecord record) {
try {
String timestampStr = record.get("Timestamp");
String code = record.get("Code");
String state = record.get("State");
String isppe = record.get("ISPPE"); // 作为唯一标识 key
Instant timestamp = Instant.parse(timestampStr); // 自动支持 ISO-8601 + 时区(如 T13:03:22.653+0200)
return new CsvEvent(timestamp, code.trim(), state.trim(), Long.parseLong(isppe));
} catch (Exception e) {
// 记录警告日志,跳过脏数据行
log.warn("Skip invalid CSV record: {}", record, e);
return null;
}
}</csvevent>
?
CsvEvent是轻量数据载体类(含Instant timestamp,String code,String state,long isppe)。
✅ 2. 建模状态流转规则(有限状态机)
根据需求,合法流转路径为:
-
UN→ACK或RTNUN -
ACK/RTNUN→NORM -
UPR→NORM - 其他任意组合均为非法,跳过计算
可封装为静态校验方法:
public static boolean isValidTransition(String fromState, String toState) {
return switch (fromState) {
case "UN" -> "ACK".equals(toState) || "RTNUN".equals(toState);
case "ACK", "RTNUN" -> "NORM".equals(toState);
case "UPR" -> "NORM".equals(toState);
default -> false;
};
}
✅ 3. 按 Code 分组 + 有序状态链匹配,计算时间差
核心难点在于:同一 Code 的事件可能跨多行、非连续出现,且需严格按时间顺序匹配合法状态对(如 UN→ACK,而非 ACK→UN)。推荐步骤:
-
按
Code分组:确保同组内事件属于同一业务实体; -
组内按
Timestamp升序排序:保证状态流时间正确性; -
滑动窗口扫描:对每组事件,遍历相邻两行,检查
(prev.state → curr.state)是否合法; -
记录结果:以
ISPPE(即问题中的“key”)为标识,存储Duration.toMillis()差值。
完整计算逻辑:
Instant.parse()
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











