File
把其他程序写在本地或网络文件夹中某个文件里的值(试验机的 CSV、数据记录仪的日志、JSON 或 XML 格式的结果)作为点位读取,并为其他程序写入行或整个文件:“文件夹和文件”“文件文本”“写入”三张卡片,点位在每种格式中读取什么,收件文件夹,为每一列或每个字段提供一个点位的扫描,三个完整示例,以及驱动不做的事。
File 驱动读取其他程序写入文件的值:试验机在每个样品之后追加一行的 CSV、数据记录仪的日志、JSON 或 XML 格式的结果文件、只含一个批号的文本文件。每个点位读取文件中的一个值,它的值和其他任何点位的值一样送达各处:Logic、仪表画面,以及 Process 测试台的运行记录。在设备允许时,驱动也为其他程序写入:向文件追加一行,或替换整个文件。
读取是主要用途,只需要三个答案:文件夹、文件和它的格式。文件文本的读法(编码、列分隔符、小数分隔符)在保持识别时从文件本身读出,扫描为每一列或每个字段提供一个点位,每个点位新建时都是只读。属于写入的内容,只有在设备打开写入之后才会出现。
本驱动的一台设备就是一个文件夹以及它在其中读取的文件:同一文件夹中的两个文件是两台设备。文件夹是驱动器加文件夹(C:\TestMachine\Logs),或网络共享加其下的文件夹(\\lab-pc\results),工作站用运行它的账户的 Windows 权限访问它。设备位于驱动之下,可以归入文件夹,与任何没有串行线路也没有 MQTT Broker 的驱动一样,形成 驱动 → 文件夹 → 设备 → 点位。
驱动页面
标题下的一行写着“每台设备读取一个文件,或到达某个文件夹的文件。添加设备,填写其文件夹、文件和格式,然后扫描它,把其中的值添加为点位。”对有“配置 Connector”权限的角色,页面上有本驱动自己的扫描范围卡片,里面是扫描要读取的文件(见设备发现)。它下面是任何驱动都有的设备表(见设备表),用标题右侧的添加设备增加;为空时显示“还没有设备。”驱动的命令栏上有发现设备,在扫描范围卡片填写完整之前呈灰色。本驱动列在文件和数据库之下,在每个驱动列表中,这个类别位于 Web 与 API 和测试之间。
设备
本驱动的设备没有“连接”卡片:文件夹和文件卡片占据它的位置,后面是文件文本卡片,在读取单个文件的设备上还有写入卡片。“设备”卡片的轮询间隔(ms)默认为 1000,表示点位多久读取一次文件,与任何驱动一样,每个点位都可以覆盖它。
新设备没有文件夹:显示“尚未填写文件夹”,它的页面写着“在这台设备填写文件夹之前,工作站不会读取它,因此暂时不读取任何数据,也没有错误可显示。在下面的‘文件夹和文件’卡片里填写文件夹,工作站就会开始读取。”在填写文件夹之前不读取任何内容。标题栏显示的 Base URI 就是运行时地址,文件夹和名称以 URI 形式书写,后面是没有设为识别的设置:file://single?folder=C%3A%5CTestMachine%5CLogs&name=Log_%7Byyyy-MM-dd%7D.csv&format=delimited,收件文件夹则为 file://inbox?...。
“文件夹和文件”卡片
| 字段 | 含义 | 默认值 |
|---|---|---|
| 文件夹路径 | “驱动器加文件夹,或网络共享。访问文件夹时使用运行工作站的账户的 Windows 权限。”框中以 C:\TestMachine\Logs 作为提示。 |
空 |
| 文件名 | 在读取单个文件的设备上:“文件夹内的名称。花括号中的部分是工作站的日期和时间:Log_.csv 每天都是一个新文件。”名称可以包含该文件夹的子文件夹(results\last.csv)。 |
空 |
| 要读取的文件 | 收件文件夹上的同一个框:“要读取的文件,直接位于文件夹中:* 代表任意字符,? 代表一个字符,例如 Test_*.csv。” | 空 |
| 读取来源 | 单个文件:“文件每次变化都会重新读取。不断增长的文件从上次读取停止的位置继续读取。”收件文件夹:“每个新文件按到达顺序读取一次,然后移到子文件夹 Processed。不会删除任何文件。” | 单个文件 |
| 文件格式 | CSV 与分列文本、自由文本、JSON 或 XML:点位在文件中找到其值的方式(见点位寻址)。 | CSV 与分列文本 |
带日期部分的名称用花括号书写,里面是 .NET 日期时间格式,按工作站自己的时钟:Log_{yyyy-MM-dd}.csv 今天是 Log_2026-10-03.csv,过了午夜就是第二天的文件,而 Data_{yyyy-MM}.txt 每月更换一次。框下方,卡片显示它现在对应哪个文件:“今天:Log_2026-10-03.csv”。双写的花括号 {{ 和 }} 是名称中的花括号。日期部分从不写冒号,因为文件名不允许冒号:写 {HH-mm},不写 {HH:mm}。
设备运行后,卡片会说明它读取的是哪个文件:
| 卡片显示 | 时机 |
|---|---|
| “正在读取:Log_2026-10-03.csv” | 正在使用的文件,即设备现在读取的文件。 |
| “正在读取:Log_2026-10-03.csv(尚不存在)” | 文件尚不存在:它的点位等待,设备保持在线。 |
| “此名称由点位写入。重启后,设备会重新读取配置的文件。” | 读取文件名的点位被写入,把设备指向了另一个文件(见写入)。 |
| “收件文件夹中有 3 个文件等待处理” | 收件文件夹中,还有符合其模式、尚待读取的文件(只有一个时为“收件文件夹中有 1 个文件等待处理”)。 |
卡片无法接受的设置会在卡片下方说明,改正之前设备不会保存:
| 你输入 | 卡片显示 |
|---|---|
不是完整路径的文件夹,例如 Logs |
“文件夹必须是完整路径:驱动器加文件夹(C:\Test),或网络共享加其下的文件夹(\server\tests)。” |
含有文件夹名称不允许的字符的文件夹,或下面没有文件夹的共享(\\server) |
“文件夹包含文件夹名称不允许的字符,或者是下面没有文件夹的网络共享。” |
| 没有文件名 | 不会被拒绝:设备照常保存并等待,显示“尚未填写文件名”(收件文件夹显示“尚未填写要读取的文件”),直到填写名称。 |
把完整路径作为名称,例如 C:\Logs\last.csv |
“文件名是文件夹内的名称,而不是完整路径:文件夹应填写在‘文件夹路径’框中。” |
含 .. 的名称,例如 ..\other\last.csv |
“文件名用 ".." 跳出了文件夹。驱动从不离开自己的文件夹。” |
含 : 或其他文件名不允许的字符的名称,或某一部分以句点或空格结尾 |
“文件名包含文件名不允许的字符(例如 : 或 |),或者某一部分以句点或空格结尾。日期部分不能写入冒号:请使用 ,而不是 。” |
Windows 保留给设备的名称,例如 CON 或 COM1 |
“Windows 将此名称保留给设备使用(CON、NUL、COM1 等)。请另选一个。” |
读取单个文件的设备上出现 * 或 ? |
“只有收件文件夹的模式可以使用 * 或 ?。请指定一个文件的名称,或改为从收件文件夹读取。” |
| 收件文件夹的模式中含子文件夹 | “收件文件夹就是文件夹本身:请把子文件夹填在‘文件夹路径’框中,这里只保留模式。” |
| 日期部分没有闭合,或不是日期格式 | “名称中的日期部分没有闭合,或不是日期格式。请把它写在花括号中,例如 Log_.csv。” |
保存时遵守相同的规则,拒绝时操作记录条会这样说:“设备‘Tensile tester’有驱动无法使用的文件设置。请打开它并修正面板标出的字段。”
“文件文本”卡片
文件的字符、列和数字如何读取。每项设置一开始都是从文件识别,驱动从正在使用的文件中读出它。保持这样的设置下方,在设备读过文件之后,会有一行说明它发现了什么,例如“在文件中发现:UTF-8”。对于前几行看不出来的文件,可以选择任一设置把它固定下来。
| 字段 | 显示条件 | 选项 | 默认值 |
|---|---|---|---|
| 编码 | 始终 | 从文件识别、UTF-8、Windows-1252 (ANSI)(旧 Windows 程序的编码) |
从文件识别 |
| 列分隔符 | CSV | 从文件识别、分号 (;)、逗号 (,)、制表符 | 从文件识别 |
| 小数分隔符 | 始终 | 从文件识别、小数点 (12.5)、小数逗号 (12,5) | 从文件识别 |
| 标题行 | CSV | 0 到 1000:“包含列名的行,从 1 开始计数;文件没有标题行时为 0。”它之前的行被跳过。 | 1 |
| 设置 | 识别时读取的内容 |
|---|---|
| 编码 | 文件开头的字节顺序标记,它优先于任何选择;否则,字节是有效的 UTF-8 时为 UTF-8;否则为 Windows-1252。 |
| 列分隔符 | 制表符、分号和逗号中,第一个能把前几行分成相同列数的那个;第一行不含其中任何一个时,文件只有一列。 |
| 小数分隔符 | 文件中数字之间带逗号的比带点的多时为逗号;否则为点。JSON 数字总是带点;该设置适用于以文本书写的数字。 |
“写入”卡片
读取单个文件的设备有写入卡片;收件文件夹只被读取,没有这张卡片。
| 字段 | 显示条件 | 含义 | 默认值 |
|---|---|---|---|
| 允许写入 | 始终 | 关闭时:“该设备只读取。要追加行、替换文件或在工作站运行时切换到另一个文件,请打开写入。”打开时:“此设备的点位可以写入文件。在访问方式另行设置之前,每个点位仍然只读取。” | 关闭 |
| 标题文本 | 写入打开,CSV 或自由文本 | “写入操作新建文件时首先写入的内容,例如 Time;Pressure。”一行,不含换行。 | 空 |
| 行尾 | 写入打开 | 从文件识别(文件自己的行尾,新文件为 CR LF)、CR LF(与 Windows 相同) 或 LF。 | 从文件识别 |
只有在设备没有任何点位写入时,才能关闭写入。仍有点位写入时,开关保持显示并呈灰色,并说明原因:“此设备有 2 个点位会写入文件。关闭写入前,请先把它们设为只读。”(只有一个点位时为“此设备有一个点位会写入文件。关闭写入前,请先把它设为只读。”)。
在线、等待和离线
| 情况 | 设备及其点位的行为 |
|---|---|
| 没有填写文件夹 | 设备等待:“尚未填写文件夹”,灰点,不读取任何内容,也没有错误。 |
| 已填写文件夹,没有文件名 | 设备等待:“尚未填写文件名”,灰点,不读取任何内容,也没有错误;它的页面写着“在这台设备填写文件名之前,工作站不会读取它,因此暂时不读取任何数据,也没有错误可显示。在下面的‘文件夹和文件’卡片里填写文件名,工作站就会开始读取。” |
| 收件文件夹,已填写文件夹,没有要读取的文件 | 设备等待:“尚未填写要读取的文件”,灰点,不读取任何内容,也没有错误;它的页面写着“在这台设备填写要读取的文件之前,工作站不会读取它,因此暂时不读取任何数据,也没有错误可显示。在下面的‘文件夹和文件’卡片的‘要读取的文件’里填写(例如 Test_*.csv),工作站就会开始读取。” |
| 无法访问文件夹(共享已停止、驱动器不见了、账户没有访问权限) | 设备离线,其点位读取失败;最多每秒重新查看一次文件夹,文件夹恢复后设备立即连接。 |
| 能访问文件夹,但文件尚不存在 | 设备保持在线。读取值的点位没有读数并等待;文件是否存在读为假。 |
| 另一个程序占用文件且不共享 | 这一次没有读数;下一次读取再试。点位保留上一次读数,读数比其轮询间隔加 10 秒更旧时,计为读取失败,与任何驱动相同。 |
| 某个值不存在,或放不进点位的类型 | 该点位读取失败并附原因;设备继续读取其他点位。 |
点位寻址
点位读取什么
本驱动的点位没有自己的地址框:它的信号源卡片询问它读取什么,对于值,还询问值在设备格式中的位置。
| 读取内容 | 点位显示的内容 | 数据类型 |
|---|---|---|
| 数值 | 文件中的一个值,按下面设备格式的字段找到。 | Boolean、Int32、Int64、Float、Double 或 String;新点位为 Double |
| 整个文件 | 全部内容,去掉末尾的行尾:只含一个批号或一个状态的文件。最多 4 MiB。 | 同上;新点位为 String |
| 文件是否存在 | 正在使用的文件现在是否存在。 | Boolean |
| 文件大小 | 文件的字节数。 | Int64 |
| 最后修改 | 文件最后一次被写入的时间:看它变化,Logic 就知道有新数据到达。 | DateTime |
| 文件名 | 正在使用的文件在文件夹内的名称。写入时,它指定另一个文件(见写入)。 | String |
| 行数 | “统计文件中的所有行,包括标题行和空行。” | Int64 |
信号源不能读取为的类型会被拒绝,并列出可以读取为的类型:“请从可读取为的数据类型中选择一个:Int64。”选择另一个信号源会带来它自己的类型。从文件中取出的文本,按点位的类型读取,方式与 Generic serial and TCP 驱动读取消息相同,并使用文件的小数分隔符:Boolean 读取 1、true、on 或 yes 和 0、false、off 或 no,整数读取整数,String 按原样取字符,所以像 0412 这样的代码只有作为 String 才保留开头的零。
每个点位新建时都是只读,在不允许写入的设备上,访问字段不提供其他选项。设备允许写入后,读取数值或整个文件的点位可以设为读写或只写,读取文件名的点位可以设为读写;文件信息(是否存在、大小、最后修改、行数)永远不会被写入:“文件信息无法写入。请让点位保持只读。”
CSV 与分列文本
| 字段 | 显示条件 | 含义 | 默认值 |
|---|---|---|---|
| 列 | 读取数值 | “标题行中的列名,或从 1 开始计数的列号。”只含数字的文本是列号;名称不区分大小写,也忽略前后的空格。在没有标题行的文件上:“从 1 开始计数的列号。该文件没有标题行,因此列没有名称。” | 空 |
| 要读取的行 | 读取数值 | 最后、按编号或按内容。“行从标题行之后开始计数。‘按内容’读取键列包含键值的最后一行。” | 最后 |
| 行号 | 按编号 | 数据行,从标题行之后的 1 开始计数。 | 空 |
| 键列 | 按内容 | 用其值选择行的列,按名称或列号。 | 空 |
| 键值 | 按内容 | 要读取的行中键列所含的值,例如 0412。 |
空 |
用双引号括起来的字段可以包含分隔符;包含换行的字段不会被读取。字段无法工作的点位不会保存,它的页面会说明缺少什么:
| 你留空或输入 | 点位页面显示 |
|---|---|
| 没有列 | “请输入列:使用标题行中的列名或列号。” |
| 第 0 列 | “列从 1 开始计数。” |
| 在没有标题行的文件上按名称指定列 | “该文件没有标题行,因此列需用列号指定。” |
| 按编号,但没有行号 | “请输入从 1 开始计数的编号。” |
| 按内容,但没有键列 | “请输入键列:用该列的值选择行。” |
| 按内容,但没有键值 | “请输入该行包含的内容。” |
只读的源地址(总线)一行显示驱动收到的内容:column?name=Force 表示最后一行的 Force,column?number=3&row=number&rowNumber=5 表示第五行的第三列,column?name=Force&row=match&key=Sample&equals=0412 表示样品 0412 的那一行。
自由文本
| 字段 | 显示条件 | 含义 | 默认值 |
|---|---|---|---|
| 要读取的行 | 读取数值 | 最后(最后一个非空行)、按编号或按内容。“行从文件开头开始计数。‘按内容’读取包含该文本的最后一行。” | 最后 |
| 行号 | 按编号 | 行号,从文件开头的 1 开始计数。 | 空 |
| 行中包含 | 按内容 | 要读取的行中包含的一段文本,例如 Result。 |
空 |
| 数值取自 | 读取数值 | “与 Generic serial and TCP 驱动的选项相同:整行、固定位置、分隔符之间的字段,或正则表达式。”选项与该驱动相同,只是第一项按行命名:整行、固定位置(起始字符和长度)、分隔符之间的字段(分隔符和字段序号)和模式中的捕获组(模式)。 | 整行 |
位置和字段从 1 开始计数,模式是 .NET 正则表达式,恰好有一个包住数值的捕获组,读取时间超过 250 ms 的行不会被读取。拒绝信息与通用驱动本身相同,例如“请填写数值的第一个字符位置,从 1 开始数。”或“模式必须恰好有一个包住数值的捕获组。”总线地址写作 line 加上适用的部分,例如 line?row=match&contains=Result&extract=regex&pattern=...。
JSON 与 XML
| 字段 | 格式 | 含义 |
|---|---|---|
| JSON 路径 | JSON | “成员之间用点分隔,位置写在方括号中并从 0 开始,例如 result.force 或 items[0].value。”名称中含点的成员写作 ['flow.rate']。 |
| XML 路径 | XML | “从根开始的元素用斜杠分隔,元素重复处写从 1 开始的位置,最后是属性,例如 Result/Force 或 Result/@unit。”名称按本地名称匹配,忽略命名空间前缀。 |
JSON 数字、true 或 false 按原样取用,字符串按点位的类型读取;对象或列表只能作为 String 读取,即它的 JSON。JSON 或 XML 文档在变化时整体读取,最多 4 MiB,不读取任何 DTD。总线地址为 json?path=result.force 或 xml?path=Result%2FForce。
| 你留空或输入 | 点位页面显示 |
|---|---|
| 没有路径 | “请输入值的路径。要读取整个文件,请选择‘整个文件’。” |
| 无法解析的 JSON 路径 | “这不是 JSON 路径:成员用点分隔,位置写在方括号中,例如 result.items[0].value。” |
| 无法解析的 XML 路径 | “这不是 XML 路径:元素用斜杠分隔,位置写成 Item[2] 这样,最后是属性,例如 @unit。” |
读取
每次读取时,驱动向 Windows 询问文件的大小和时间,这在网络共享上同样有效,而 Windows 的变更通知在那里无效;只有其中之一变化时才打开文件。它总是以共享读、写和删除的方式打开文件,因此写入该文件的程序从不会被阻塞。
| 文件 | 读取的做法 |
|---|---|
| 变大了,并且开头和结尾仍在原处 | 只读取新增的部分,从不重新读取整个文件:几兆字节的日志,代价只是它的新行。 |
| 变短了、被重写或被重新创建 | 从头重新读取。 |
| 以尚未被行尾结束的一行结尾 | 这一行等待,确保从不读到写了一半的值;文件 2 秒内没有变化后,它作为最后一行读取。 |
| JSON、XML,或读取整个文件的点位 | 变化时整体读取,最多 4 MiB;无法解析且变化不到 2 秒的文档视为仍在写入,点位等待。 |
| 有超过 1 MiB 的行 | 不是按行的文本:它的点位读取失败。 |
每个读数的时间戳是文件的最后修改时间,而不是读取的时刻,所以运行记录会把样品放在另一个程序写入它的时刻。
收件文件夹
读取来源设为收件文件夹,用于每个样品写一个文件的设备(Test_0412.json、Test_0413.json……):每个符合模式的新文件按到达顺序读取一次。
| 步骤 | 发生的事 |
|---|---|
| 文件到达 | 文件的大小和时间保持 1 秒不变,并且没有程序为写入而打开它时,才会被取用。 |
| 先读哪个 | 先创建的,其次先写入的,再按名称。同时到达的两个文件分两轮读取:不会跳过任何一个。 |
| 它的读数 | 设备的每个点位都读取这个文件,该文件就是一个读数,时间戳为文件的时间:运行记录会记录每一个。文件名说明这些值来自哪个文件。 |
| 每个点位都读过之后 | 文件被移到子文件夹 Processed,该子文件夹由驱动创建,名称在每种语言中都相同,因为其他程序可能会查找它;那里已有同名文件时,改名为 name (2).json。在下一个文件之前,它的值仍是点位的读数。 |
| 移动失败 | 每次读取时重试;在此期间不会再次读取该文件。 |
| 移动前工作站重启 | 文件会被再次读取:宁可一个读数计两次,也不丢失一个。 |
从不删除任何内容:子文件夹 Processed 会一直增长,直到有人清空它。收件文件夹从不被写入。
写入
在读取单个文件且允许写入的设备上,读取数值或整个文件、访问方式包含写的点位,会说明一次写入做什么:
| 字段 | 显示条件 | 含义 | 默认值 |
|---|---|---|---|
| 写入方式 | 点位会写入 | 追加一行:“在文件末尾追加一行。每次写入都有效,不会因为更新的写入而丢弃。”替换文件:“通过临时文件用该值替换整个文件,因此不会有程序读到写了一半的文件。” | 追加一行 |
| 行模板 | 追加一行 | “留空时,写入的值就是整行。 表示值, 表示写入时刻,需要时在冒号后加格式,例如 。”框中以 {datetime};{value} 作为提示。 |
空 |
| 模板 | 写入 12.5 时追加 |
|---|---|
| 空 | 12.5 |
{datetime};{value} |
2026-10-03 14:05:12;12.5 |
{datetime:dd/MM/yyyy HH:mm};{value:0.00} |
03/10/2026 14:05;12.50 |
{value:FORMAT} 接受 .NET 数字格式,{datetime:FORMAT} 接受 .NET 日期时间格式,按工作站的时钟,未给出时为 yyyy-MM-dd HH:mm:ss。数字用文件的小数分隔符书写,所以同一个模板在使用逗号的文件中写成 12,50。Boolean 点位的模板可以省略 {value}:写入真时会追加该行,就像一条命令。驱动无法填充的模板会在点位页面上被拒绝:
| 你输入 | 点位页面显示 |
|---|---|
既不是 {value} 也不是 {datetime} 的部分,或未闭合的花括号 |
“模板可使用 和 ,需要时在冒号后加格式。{{ 和 }} 表示行中的花括号。” |
不是 Boolean 的点位上没有 {value} |
“模板中没有 ,因此写入的值永远不会进入文件。只有布尔型点位可以省略它:写入真时会追加该行。” |
| 换行 | “模板只能是一行,不能包含换行。” |
| 在不允许写入的设备上会写入的点位 | “该设备不允许写入。请在设备中打开写入,或让点位保持只读。” |
| 一次写入 | 如何进行 |
|---|---|
| 追加一行 | 这一行一次写完,并在写入计为完成之前刷新到磁盘。写入新建的文件先写入标题文本;最后一行没有行尾的文件,先补上一个行尾,使这一行完整。含换行的值会被拒绝。每次写入都有效:仍在设备队列中等待的写入,从不会因为发往同一点位的更新写入而被丢弃,与命令从不被丢弃一样。 |
| 替换文件 | 值写入文件旁边的临时文件并刷新到磁盘,然后一步取代原文件。仍在等待的较新值会取代较旧的值,与任何设定值一样。 |
| 文件名 | 读取文件名、设为读写的点位,写入另一个名称后,设备从此改为读写同一文件夹中的那个文件:“在此写入一个名称后,设备从此读写同一文件夹中的该文件。文件夹之外的名称会被拒绝。”完整路径、..、: 或 Windows 保留的名称会被拒绝。设备重新连接时(包括重启),它会重新读取配置的文件。 |
| 文本 | 使用文件自身的编码、行尾和小数分隔符,在设备保持识别的地方从文件中读出。新文件为不带字节顺序标记的 UTF-8,使用 CR LF 和小数点,除非设备另有设置。 |
| 应答 | 完成,或附原因拒绝:设备不允许写入、账户没有权限、文件已标记为只读(清除该属性后,下一次写入即可完成)、磁盘已满,或文件在另一个程序中打开。只要有任何程序打开该文件,替换文件就会被拒绝;追加一行只在某个程序不共享地占用该文件时被拒绝。该程序关闭文件后,下一次写入即可完成。 |
名称所指向的文件夹和子文件夹,会在写入需要时创建,并且总在设备的文件夹之内。
设备发现
“扫描范围”卡片
对有“配置 Connector”权限的角色,驱动页面上有它的扫描范围卡片,卡片下方的一行是“读取一个文件,为找到的每个列或字段以及文件信息各提供一个点位。请选择设备以读取其文件,或输入文件夹、文件和格式。”
| 字段 | 含义 | 默认值 |
|---|---|---|
| 要扫描的文件 | 在此输入的文件,或按名称选择本驱动的一台设备。设备的文件按设备保存的设置读取,设备尚待保存的修改会先保存。 | 在此输入的文件 |
| 文件夹路径 | 输入的文件:文件夹,与设备上相同。 | 空 |
| 文件名 或 要读取的文件 | 输入的文件:名称,或收件文件夹的模式。 | 空 |
| 读取来源 | 输入的文件:单个文件或收件文件夹。 | 单个文件 |
| 文件格式 | 输入的文件:格式。输入的文件的所有文本设置都会被识别,包括标题行:第一行的字段都不是数字而下一行有数字时,第一行就是标题行。 | CSV 与分列文本 |
范围仍缺少的内容会以红字显示在卡片下方,范围完整之前,发现设备一直呈灰色:
| 范围 | 卡片显示 |
|---|---|
| 输入的文件没有文件夹 | “请输入文件所在的文件夹。” |
| 输入的文件夹不是完整路径 | “‘Logs’不是本工作站可以读取的文件夹。请填写完整路径,例如 C:\Test 或 \server\tests。” |
| 输入的名称不是该文件夹中的文件 | “‘..\last.csv’不是文件夹内某个文件的名称。” |
| 已不存在的设备 | “所选的扫描设备已不存在。请另选一个要扫描的文件。” |
| 没有文件夹或文件的设备 | “设备‘Tensile tester’尚未设置文件夹或文件,或有驱动无法使用的设置。请先填写其‘文件夹和文件’卡片。” |
要扫描的设备有无法保存的修改时,扫描不会开始:“设备发现没有开始,因为要扫描的设备的修改无法保存。”
扫描提供的内容
扫描读取单文件设备现在读取的文件,或收件文件夹中最新的文件(扫描不移动它);文件不存在、文件夹无法访问、文档无法解析,都会使扫描附原因结束。它提供一个候选项,把找到的值作为候选点位,全部为只读:
| 格式 | 候选点位 |
|---|---|
| CSV | 每列一个,读取最后一行,以标题命名(标题没有为它命名或命名重复时用列号),类型按其前几行的值确定:所有值都是数字时为 Double,都是 true 或 false 时为 Boolean,否则为 String。开头带零的代码,例如 0412,仍是 String。 |
| 自由文本 | 最后一行,String。 |
| JSON、XML | 每个值一个,按其路径命名和寻址,最多 500 个;JSON 列表提供前 20 项,遍历深入 8 层。 |
| 每种格式 | 文件信息:文件是否存在、文件大小、最后修改、文件名和行数。 |
一次扫描最多提供 500 个值,CSV 文件的列也算在内;在此截断的扫描会在结束扫描的那一行和扫描结果上方显示“result.json 的扫描提前停止。一次扫描最多提供 500 个值:请按列、JSON 路径或 XML 路径将其余的值添加为点位。”
输入的文件的候选项以文件命名(run.csv 为 run),名称带日期部分或是收件文件夹时,以文件夹命名。文件夹、名称和读取来源都已被本驱动某台设备读取的候选项(被扫描的设备,或另一台相同的设备),标为已经配置过:它的卡片只列出该设备尚无点位读取的值,并已勾选,添加所选点位位于打开之前,把勾选的值添加到该设备,均为只读。扫描的其余行为见设备发现。
设备自己的页面不经过驱动页面也能做同样的事:“点位”卡片标题栏里的发现点位按设备保存的样子读它的文件,只列出它还没有点位的值(见发现一台设备的点位)。
示例:试验机的每日 CSV
一台拉伸试验机每天在 C:\TestMachine\Logs 中写一个 CSV,名为 Log_2026-10-03.csv,标题行为 Sample;Force;Elongation,每个样品之后写一行,例如 0412;12,5;3,1。按简单路径读取它:
- 在驱动页面点添加设备;命名为
Tensile tester。 - 在文件夹和文件卡片中,文件夹路径填写
C:\TestMachine\Logs,文件名填写Log_{yyyy-MM-dd}.csv;保持单个文件和 CSV 与分列文本。卡片显示“今天:Log_2026-10-03.csv”,设备读取它之后显示“正在读取:Log_2026-10-03.csv”。文件文本卡片保持从文件识别:它会找出分号和小数逗号。 - 在驱动页面的要扫描的文件中选择
Tensile tester,然后点发现设备。候选项标为已经配置过,列出Sample(String,保留0412的零)、Force和Elongation(Double),以及文件信息。点添加所选点位。
每个点位读取最后一行;最后修改随每个新样品变化,Logic 的动作由此知道有样品到达。到了午夜,设备转向第二天的文件,在试验机写出它之前,这些值没有读数,文件是否存在读为假。智能体用工具也能做到:
device_upsert name="Tensile tester" driver=File fileFolder="C:\TestMachine\Logs" fileName="Log_{yyyy-MM-dd}.csv" fileFormat=Delimited
device_discover driver=File fileDevice="Tensile tester"
tag_upsert device="Tensile tester" name=Force address=Force opcUaType=Double
tag_upsert device="Tensile tester" name=Sample address=Sample opcUaType=String
tag_upsert device="Tensile tester" name="Last change" fileSource=Modified
示例:JSON 结果文件的收件文件夹
一个试验单元每个样品在 C:\Results\Inbox 中放一个结果文件,例如内容为 {"sample":"0413","result":{"force":12.5,"ok":true}} 的 Test_0413.json:
- 点添加设备;命名为
Results,文件夹路径为C:\Results\Inbox,读取来源为收件文件夹,要读取的文件为Test_*.json,文件格式为 JSON。 - 添加点位
Force,JSON 路径result.force,Double;添加点位Pass,JSON 路径result.ok,Boolean;添加点位Sample,JSON 路径sample,String。 - 添加点位
Source file,读取内容为文件名:它显示这些值来自哪个文件。
每个文件在静止 1 秒且没有程序为写入而打开它之后读取一次,按文件到达的顺序;每个文件都是单独的一个读数,时间戳为文件的时间;每个点位都读过之后,它被移到 C:\Results\Inbox\Processed。不会删除任何内容。用工具:
device_upsert name=Results driver=File fileFolder="C:\Results\Inbox" fileName="Test_*.json" fileMode=Inbox fileFormat=Json
tag_upsert device=Results name=Force address=result.force opcUaType=Double
tag_upsert device=Results name=Pass address=result.ok opcUaType=Boolean
tag_upsert device=Results name=Sample address=sample opcUaType=String
tag_upsert device=Results name="Source file" fileSource=Name
示例:为另一个程序追加一行
另一个程序读取 D:\Records\run.csv,每秒一行,包含时间和压力:
- 点添加设备;命名为
Run log,文件夹路径为D:\Records,文件名为run.csv。 - 在写入卡片中打开允许写入,标题文本填写
Time;Pressure。 - 添加点位
Line,Double,访问为只写,写入方式为追加一行,行模板为{datetime};{value:0.00}。
向 Line 写入 12.5 会追加 2026-10-03 14:05:12;12.50,文件已使用逗号或小数分隔符设为小数逗号 (12,5) 时使用逗号;写入新建的文件会先写入 Time;Pressure。快速连续的写入全部保留,并保持顺序。要每次运行写一个文件,再添加一个点位 File,读取内容为文件名,读写:运行开始时,Logic 写入序列号加 .csv,之后的行就写进那个文件。用工具:
device_upsert name="Run log" driver=File fileFolder="D:\Records" fileName=run.csv fileFormat=Delimited fileWrites=true fileHeaderText="Time;Pressure"
tag_upsert device="Run log" name=Line opcUaType=Double accessType=WriteOnly fileWriteMode=AppendLine fileLineTemplate="{datetime};{value:0.00}"
tag_upsert device="Run log" name=File fileSource=Name accessType=ReadAndWrite
智能体工具
driver_capabilities 在 file 下描述本驱动:简单路径、设备的每个字段、文件夹规则以及只能在该文件夹内操作的限制、文件名的各种形式、两种读取方式、各格式及其地址语法、各信号源及其类型、文本设置、读取与写入的行为、设备发现,以及三个完整示例。device_upsert driver=File 接受 fileFolder、fileName、fileMode(默认的 SingleFile 或 Inbox)、fileFormat(默认的 Delimited、Text、Json 或 Xml)、fileEncoding(Automatic、Utf8 或 Windows1252)、fileSeparator(Automatic、Semicolon、Comma 或 Tab)、fileDecimal(Automatic、Point 或 Comma)、fileHeaderRow(0 到 1000)、fileWrites,以及写入打开时的 fileHeaderText 和 fileLineEnd(Automatic、CrLf 或 Lf);它返回的设备带有 file,其中的 fileStatus 是运行中的驱动发现的内容:正在使用的文件、它是否存在、读到的编码、分隔符和行尾,以及收件文件夹中等待的文件。tag_upsert 接受 fileSource(Value、WholeFile、Exists、Size、Modified、Name 或 Lines)、fileRow(Last、Number 或 Matching)、fileRowNumber、fileKeyColumn、fileMatchText、fileWriteMode(AppendLine 或 ReplaceFile)和 fileLineTemplate;列或路径就是 address,自由文本的值使用通用驱动的 valueExtraction、valueStart、valueLength、valueSeparator、valueField 和 valuePattern,新点位为只读,除非 opcUaType 另行指定,否则取信号源自身的类型。device_discover driver=File 读取 fileDevice(本驱动一台设备的名称),或者为扫描输入的 fileFolder、fileName、fileMode 和 fileFormat;已配置设备缺少的点位用 tag_upsert 添加。connector_browse 为每台设备返回 fileFolder、fileName、fileMode 和 fileFormat。其他工具见智能体工具。
值得了解的限制
- 不读取 Excel 工作簿:工作簿要等它的程序另存为 CSV 后才能读取。
- 驱动从不删除文件。收件文件夹把读过的文件移到
Processed,唯一会被移除的只有替换失败时的临时文件。 - “读取文件夹中最新的文件”不是一种读取方式:它会丢失同时到达的文件,还可能显示上一个样品的值。每个样品写一个文件的设备,用收件文件夹读取。
- 不会在文件内原地修改某个值(CSV 的一个单元格、另一个程序的 JSON 中的一个成员):写入只追加一行或替换整个文件,因为两个程序写同一个文件,可能会丢失对方的修改。
- 网络共享用运行工作站的账户的 Windows 权限访问:设备不保存用户名和密码,所以共享必须允许该账户进入(读取;对于会写入的设备或收件文件夹,还要能写入和移动)。
- 驱动从不触碰其文件夹以外的任何内容:指向别处的名称,在输入时和写入时都会被拒绝。
- 每次读取时查看文件:变化在下一次读取时才会看到,而不是另一个程序写入的那一刻。
- 包含换行的 CSV 字段不会被读取,JSON、XML 或整个文件的点位最多读取 4 MiB。