CAPL 文件读写验证:先确认数据完整,再分析 CSV
问题:调用成功,数据仍可能错误
文件打开成功、连续几次读取成功、统计图也看起来合理,并不能证明读的是目标文件、每次读到的都是完整记录,或导出包含了全部样本。本指南用可以手工核对的小型临时文件,将这些问题分别验证。
适用范围是本地 CANoe/CAPL 工作流,每个物理文本行只包含一个数值时间戳。它不是通用 CSV 解析器、二进制 Trace 转换器,也不是分布式测试方案。下文的 API 行为以本站持有授权的 Vector 参考资料为依据;验证矩阵是本站编写的检查方法,并非已经执行的 CANoe 编译或实测结果。
打开文件前,先写清输入输出约定
明确预期目录、文件名、编码、时间单位、最大记录长度、记录数量和空行处理方式。测试文件与测量原件分开保存。第一轮只使用 ASCII 数字和小数点,避免编码问题掩盖记录边界错误。
| 要做的事 | 可采用的选择 | 防止的错误 |
|---|---|---|
| 重建一个完整的临时导出文件 | 文本覆盖,模式 0 | 混入上一段记录 |
| 继续写入已知文本文件 | 先检查末尾分隔符和时间连续性,再使用追加模式 2 | 两条记录粘连或时间戳重新归零 |
| 保留判断行边界所需的信息 | fileGetString,加有长度上限的记录组装 | 把一次读取的片段误当成整行 |
| 读取已确认足够短、结果不需要 LF 的文本行 | fileGetStringSZ,并验证长度上限 | 减少去换行步骤;仍不能省略超长记录检查 |
| 读取二进制采集文件 | 使用理解该文件格式的二进制处理流程 | 把任意字节当成数值文本 |
根据可用参考资料,openFileRead(英文参考)先搜索数据库所在目录,再使用当前配置目录。openFileWrite(英文参考)使用相对文件名,输出基目录由写路径决定,未设置时使用配置目录。两者的定位规则不同。因此,回读同名文件,不等于已经读到刚刚写出的那个文件。
用独特文件名和可辨认的标记内容确认实际来源。打开前准备并核对输出目录,不要假定 API 自动创建目录。setWritePath 的可用参考明确排除了分布式环境,迁移该方案前必须核实安装版本和环境支持。
将读取、组装和数值解析分开
可靠的处理顺序是:读取成功 → 得到长度受控的完整记录 → 验证数值。第一步成功,不能跳过第二步。
例如缓冲容量为 8 时,一次调用最多读取 7 个字符。对于 123456789 这一行,先读到的 1234567 本身也是合法数字,但不是正确记录。确定完整记录以前,不要更新样本计数或统计值。超过约定记录长度时,应报出记录位置并拒绝导入;如果选择跳过,就必须丢弃到该记录的真正边界,不能把剩余后缀当作下一条时间戳。
fileGetString 遇到行边界时会在结果中保留 LF;fileGetStringSZ 不把 LF 放进结果。两者都受 buffsize - 1 限制。CANoe 12 原始帮助的 fileGetStringSZ 说明列出了 LF 和 CRLF(DOS)两种行尾。下面分别测试两种夹具及返回字节;支持的输入形式本身不能证明所有安装版本的字节归一化行为相同。
每次尝试读取前,使应用层的当前记录失效;只有读取成功才继续解析。不要依赖失败调用清空缓冲区。否则,在最后一条记录之后读取失败时,旧内容可能再次被统计,造成重复时间戳。
可用文档将读取返回值定义为 1 或 0,并把 0 描述为错误,没有给出可以单独证明“正常到达 EOF”的返回约定。因此,尚未解释的停止应记录为“读取终止”。对于测试文件,可核对已知数量与内容;对于生产数据的完整性,需要使用安装版本明确支持的诊断方法,或其他独立的完整性检查。读了一部分就停止,不能自动视为一个有效的小数据集。
用小文件建立验证矩阵
表中的 \n 表示 LF,\r\n 表示 CRLF;制作测试文件时应写入实际分隔符,而非反斜杠字面字符。以下为设计输入与预期的应用行为,不是已执行结果。
| 测试文件或操作 | 要观察什么 | 验收条件 |
|---|---|---|
0\n10\n20\n |
读取片段、有效记录和最后一次读取状态 | 按顺序得到三个值,不重复最后一个值 |
| 相同数值改用 CRLF | 返回字符及解析后的值 | 按声明的行尾规则得到相同数值记录 |
| 空文件 | 是否错误处理了旧缓冲内容 | 零个值,并明确报告输入为空 |
0\n\n10\n |
中间的空物理行 | 明确跳过或拒绝,不静默转换成 0 |
0\n10,末尾没有分隔符 |
最后一条未终止行的处理 | 明确且经过验证地接受完整末项或拒绝,不能从后续失败读取中造出记录 |
| 长度恰好到达、以及超过所选容量边界的记录 | 片段长度与组装状态 | 仅在长度约定内接受完整记录,不拆成多个时间戳 |
| 不存在的文件名 | 打开返回值 | 不使用句柄 0 继续读取 |
| 候选搜索目录中存在不同内容的同名文件 | 实际读到哪个标记 | 继续其他测试前消除来源歧义 |
临时输出文件已有 OLD\n |
模式 0 和模式 2 的差异 | 覆盖与追加符合预先约定 |
旧文件末尾为 20,再追加 30\n |
是否拼成 2030 |
应用阻止或拒绝这种不安全的追加 |
保留测试原件、CANoe 版本、当前配置、API 变体、缓冲容量、打开/读取/写入/关闭状态,以及接受的记录数。只保留最后的平均值,会丢失解释失败原因所需的证据。
写入返回值不是字节数
filePutString(英文参考)接收要写入的字符数量,成功返回 1,错误返回 0。即使请求写入 20 个字符,成功结果仍然是 1。不能拿返回值与 20 比较,更不能因为不相等就重试整条记录。
长度应来自准备写入的有效文本,而不是存储数组的容量。记录分隔符必须明确包含在文本中。任何一次写入失败后,都不能继续宣布导出成功;文档中的状态值没有说明失败时是否已经写入部分内容,因此不能假定直接重试安全。完成后检查 fileClose(英文参考)并查看实际文件;关闭成功也不能抹掉此前的写入失败。
每个句柄由一个操作负责管理。每次成功打开后,正常完成、解析拒绝和用户中止都要走清理路径。不要用新打开的结果覆盖尚未关闭的句柄,也不要在确认关闭后复用旧值。清理失败应与原始错误分别报告,并阻止该操作继续使用句柄。
将验证过的时间戳送入间隔分析工具
先完成文件往返验证,再使用一个仅含 0、10、20、31 的单列合成样本,单位选择毫秒。相邻差值应为 10、10、11 ms。手算核对这些数对后,再在报文时间间隔分析工具中比较结果。
工具接受它明确支持的时间戳列表或单列 CSV,不负责解析包含通道、ID 和数据域的通用 CANoe 日志。先提取时间戳列、保留原始顺序并确认单位。处理真实流量时,按照测量同一 CAN 报文周期的方法选定连续的单一报文流。文件完整,只能证明文件处理这一环节,不能证明选取的流量回答了原本的测量问题。
参见资料来源与验证边界。用于必须证明完整性的测试前,应对照安装版本自带帮助,核实函数签名、支持范围,以及本文来源尚未明确的 EOF 和编码细节。