如何将Emerson DeltaV fhx文件导入至任意数据库表中
基于Java的Emerson DeltaV FHX文件处理方案
一、从DeltaV服务器获取FHX文件
首先需从DeltaV服务器导出FHX文件,可通过两种方式实现:
- 调用DeltaV命令行工具:使用官方提供的
dbexport命令行工具自动导出FHX文件,Java中可通过ProcessBuilder执行该命令,示例代码如下:ProcessBuilder pb = new ProcessBuilder("dbexport.exe", "-o", "target.fhx", "-s", "DeltaVServerName"); pb.directory(new File("C:/Program Files/Emerson/DeltaV/Utilities")); Process process = pb.start(); process.waitFor(); - DeltaV UI手动导出:若无需自动化,可通过DeltaV Explorer界面选择数据库导出为FHX文件,再传输至本地。
二、方案1:FHX转XML后导入数据库
步骤1:FHX转XML
使用DeltaV官方工具FHX2XML将FHX文件转换为结构化XML,Java中可通过进程调用实现自动化转换:
ProcessBuilder pb = new ProcessBuilder("fhx2xml.exe", "-i", "source.fhx", "-o", "output.xml"); pb.directory(new File("C:/Program Files/Emerson/DeltaV/Utilities")); Process process = pb.start(); process.waitFor();
若需纯Java实现转换(不依赖DeltaV工具),可基于ANTLR定义FHX语法规则,生成解析器后自行转换为XML格式。
步骤2:XML解析并导入数据库
针对大体积XML文件(最高1GB),采用StAX流解析避免内存溢出,结合JDBC批量插入提升效率:
XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader reader = factory.createXMLEventReader(new FileInputStream("output.xml")); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/deltav_db", "user", "pass"); conn.setAutoCommit(false); PreparedStatement pstmt = conn.prepareStatement("INSERT INTO enumeration_sets(name, fixed, description) VALUES (?, ?, ?)"); while (reader.hasNext()) { XMLEvent event = reader.nextEvent(); if (event.isStartElement()) { StartElement start = event.asStartElement(); if ("ENUMERATION_SET".equals(start.getName().getLocalPart())) { String name = start.getAttributeByName(new QName("NAME")).getValue(); String fixed = start.getAttributeByName(new QName("FIXED")).getValue(); // 解析子元素DESCRIPTION String desc = ""; while (reader.hasNext()) { XMLEvent childEvent = reader.nextEvent(); if (childEvent.isStartElement() && "DESCRIPTION".equals(childEvent.asStartElement().getName().getLocalPart())) { desc = reader.nextEvent().asCharacters().getData(); break; } } pstmt.setString(1, name); pstmt.setString(2, fixed); pstmt.setString(3, desc); pstmt.addBatch(); } } } pstmt.executeBatch(); conn.commit();
需根据FHX内容设计对应数据库表(如schema_info、enumeration_sets、plant_areas等),建立关联关系。
三、方案2:直接解析FHX到数据库
步骤1:定义FHX语法规则
基于ANTLR编写FHX语法文件,识别FHX中的块结构(如SCHEMA { ... })、属性(如NAME="_OFF_ON")和注释:
grammar FHX; file: comment* block+; block: (SCHEMA | LOCALE | ENUMERATION_SET | PLANT_AREA) attribute* '{' comment* (entry | attribute)* '}'; attribute: ID '=' value; entry: ENTRY attribute* '{' attribute* '}'; value: STRING | NUMBER | BOOLEAN; comment: '/*' .*? '*/'; SCHEMA: 'SCHEMA'; LOCALE: 'LOCALE'; ENUMERATION_SET: 'ENUMERATION_SET'; PLANT_AREA: 'PLANT_AREA'; ENTRY: 'ENTRY'; ID: [a-zA-Z_][a-zA-Z0-9_]*; STRING: '"' .*? '"'; NUMBER: [0-9]+; BOOLEAN: 'T' | 'F'; WS: [ \t\n\r]+ -> skip;
使用ANTLR生成Java解析器和词法分析器类。
步骤2:解析FHX并写入数据库
通过ANTLR解析器遍历FHX文件,流式处理每个块数据,直接写入数据库:
FHXLexer lexer = new FHXLexer(CharStreams.fromFileName("source.fhx")); CommonTokenStream tokens = new CommonTokenStream(lexer); FHXParser parser = new FHXParser(tokens); ParseTree tree = parser.file(); FHXBaseListener listener = new FHXBaseListener() { @Override public void enterEnumeration_set(FHXParser.Enumeration_setContext ctx) { String name = ctx.attribute().stream() .filter(a -> "NAME".equals(a.ID().getText())) .map(a -> a.value().STRING().getText().replace("\"", "")) .findFirst().orElse(""); // 提取其他属性并执行JDBC插入 } }; ParseTreeWalker.DEFAULT.walk(listener, tree);
针对1GB级文件,需采用流式解析模式,避免一次性加载全部内容到内存。
四、性能优化建议
- 采用批量插入:每次提交1000-5000条记录,减少数据库交互次数。
- 使用连接池:如HikariCP管理数据库连接,提升连接复用率。
- 流式处理:无论是XML还是FHX解析,均采用流模式避免内存溢出。
- 异步处理:将文件解析与数据库写入分离,提升整体处理效率。
内容的提问来源于stack exchange,提问作者Purushottam kumar
相关产品推荐
相关产品推荐

