今天继续我们的小白教程,老鸟就不要在这浪费时间了😊。
前面一期我们介绍了CODESYS的文件操作库CAA File。这一期主要介绍CODESYS的SysFile库所包含的文件读写功能块,主要包括文件路径、名称、大小的获取以及文件的创建、打开、读、写、拷贝和删除功能等。
一、SysFile库简介
与上一期介绍的目录和文件操作库CAA File不同,SysFile属于CODESYS比较底层的库,其中结构和功能块的定义与C语言非常接近。使用该库需要在“库管理器”中添加SysFile库,这里使用的是3.5.15版本。
需要注意的是,SysFile库中所有功能均为函数(FUNCTION),与CAA File库中的功能块(FUNCTION_BLOCK)是不同。函数可以直接使用,而功能块需要先声明后使用。因为CODESYS的函数内部的变量在运行后是不会保留的,这个与功能块是不同。使用的时候要分清楚,避免因为初始状态不同导致的问题。
二、SysFile库的主要功能块
提供对运行时系统的文件功能的访问。仅能进行文件相关的操作。
1.基本定义
(1)文件访问模式ACCESS_MODE
定义文件打开的模式。
名称 | 初始值 | 说明 |
AM_READ | 0 | 使用读取权限打开现有文件。如果文件不存在,则报打开失败错误。 |
AM_WRITE | 1 | 创建具有写入权限的新文件。如果文件确实存在,则丢弃内容。 |
AM_APPEND | 2 | 使用附加(仅写)权限打开现有文件。如果文件不存在,则打开失败。 |
AM_READ_PLUS | 3 | 打开具有读/写权限的现有文件。如果文件不存在,则打开失败。 |
AM_WRITE_PLUS | 4 | 创建具有读/写权限的新文件。如果文件确实存在,则丢弃内容。 |
AM_APPEND_PLUS | 5 | 使用附加(读/写)访问权限打开现有文件。如果文件不存在,“打开”将创建一个新文件。 |
注意:对于所有*_PLUS模式,读取文件后,只能在调用SysFileGetPos或SysFileSetPos后才能进行写入!如果在SysFileRead之后立即调用SysFileWrite,则文件指针可能位于无效位置!正确的使用方式如下:
SysFileRead();
SysFileGetPos();
SysFileWrite();
(2)文件的时间戳SYS_FILETIME
定义文件的时间戳结构。
tCreation:文件创建时间。
tLastAccess:访问文件的时间。
tLastModification:上次修改的时间。
(3)文件状态SYS_FILE_STATUS
定义指定文件的实际文件状态。
名称 | 初始值 | 说明 |
FS_OK | 0 | 文件已被打开。 |
FS_NO_FILE | 1 | 没有可用文件。 |
FS_ILLEGAL_POS | 2 | 文件中的非法位置。 |
FS_FULL | 3 | 文件系统上没有多余空间。 |
FS_EOF | 4 | 已达到文件结尾。 |
(4)错误码定义Errors
此错误码定义位于CmpErrors库中,文件读写中常用的如下表所示:
名称 | 初始值 | 说明 |
ERR_OK | 16#0 | 操作成功 |
ERR_FAILED | 16#1 | 操作失败 |
ERR_PARAMETER | 16#2 | 参数错误 |
ERR_NO_OBJECT | 16#10 | 指定的文件不存在 |
ERR_NOTIMPLEMENTED | 16#C | 操作么有执行 |
ERR_NOT_SUPPORTED | 16#18 | 操作不支持 |
由于错误定义较多,这里只列了比较常用的几个,上表中没有列出的可以参考官方文档。
2.文件操作函数
文件操作函数如下表:
函数名称 | 功能 | 备注 |
SysFileOpen | 打开文件 | 成功则返回文件句柄 |
SysFileRead | 读取文件内容 | 返回读取的字节数 |
SysFileWrite | 写入文件 | 返回写入的字节数 |
SysFileFlush | 缓冲内容写入文件 | 返回运行系统错误码 |
SysFileClose | 关闭文件 | 返回运行系统错误码 |
SysFileCopy | 拷贝文件 | |
SysFileRename | 文件重命名 | |
SysFileDelete | 删除文件 | |
SysFileEOF | 检查文件是否到达结尾 | |
SysFileGetPos | 获取文件指针当前位置 | |
SysFileGetSize | 获取文件尺寸 | 返回值为文件尺寸 |
SysFileGetTime | 获取文件最后修改时间 | |
SysFileSetPos | 设置文件指针位置 | |
SysFileGetName | 获取文件名称 | |
SysFileGetPath | 获取文件路径 | |
SysFileGetStatus | 获取文件状态? | |
SysFileTruncate | 重新设置文件尺寸 | |
SysFileDeleteByHandle | 根据handle删除文件 | |
SysFileGetSizeByHandle | 根据handle获取文件大小 | |
SysFileGetName2 | 根据handle获取文件名称 | |
SysFileGetStatus2 | 根据handle获取文件状态 |
3.常用的函数介绍
SysFile库文件操作函数的参数比较类似,下面对几个常用的函数进行介绍。
(1)SysFileOpen
szFile:文件名称。可以包含绝对或相对路径,注意路径需要用斜杠“/”表示,不能用反斜杠“\”。
am:打开模式,类型为SysFile.ACCESS_MODE。
pResult:返回运行系统错误代码,类型为POINTER TO RTS_IEC_RESULT,含义在CMPErrors库中定义,见第一部分介绍。
返回值:成功则返回文件句柄,类型为SysFile.RTS_IEC_HANDLE,失败则返回RTS_INVALID_HANDLE。
(2)SysFileClose、SysFileFlush
hFile:文件句柄,类型为SysFile.RTS_IEC_HANDLE。
返回值:返回运行系统错误代码,类型为RTS_IEC_RESULT。
(3)SysFileRead和SysFileWrite
hFile:文件句柄。
pbyBuffer:指向读或者写缓冲区首地址,类型为POINTER TO BYTE。
ulSize:需要读取或写入的字节数。注意必须小于等于缓冲区尺寸。
pResult:返回运行系统错误代码。
返回值:成功则返回读取或写入的字节,失败则返回0。数据类型为_XWORD,实际与DWORD等价。
(4)SysFileGetSize
szFileName:文件名称
pResult:返回运行系统错误代码。
返回值:文件尺寸。
(5)SysFileGetTime
szFileName:文件名称
ptFileTime:文件时间,类型为POINTER TO SYS_FILETIME。
返回值:返回运行系统错误代码,类型为SysFile.RTS_IEC_RESULT。
注意:以上函数中凡是类型为RTS_IEC_RESULT的返回值,如果是在函数中作为输入,则需要定义为指针POINTER TO RTS_IEC_RESULT或者使用ADR()来获取错误码;如果作为函数返回值,则为SysFile.RTS_IEC_RESULT。
三、SysFile库使用示例
SysFile库的函数可以直接一起顺序使用,也可以像CAA File库中的功能块一样按状态机的方式进行操作。以下示例为文件写入的分步操作。本次测试使用的控制器是禾川的Q0,使用其它控制器时需要正确指定可进行读写操作的目录位置。
程序变量定义如下:
PROGRAM testSysFile
VAR
bExecute : BOOL;
szFileName : STRING:='/testfile.txt';
pbyBuffer : POINTER TO BYTE;
ulSize : DWORD;
ErrorCode : INT;
Done : BOOL;
stContent : STRING:='hello everyone!';
Mode : SysFile.ACCESS_MODE := 1; //0-AM_READ; 1-AM_WRITE; 2-AM_APPEND; 3-AM_READ_PLUS; 4-AM_WRITE_PLUS; 5-AM_APPEND_PLUS
iStep : INT := 0; //运转流程
OP_TRIG : R_TRIG;
bError : BOOL;
hFile : SysFile.RTS_IEC_HANDLE;
pRes : SysFile.RTS_IEC_RESULT;
iRet : DWORD;
END_VAR
程序如下:
bExecute:=TRUE;
OP_TRIG(CLK := bExecute);
pbyBuffer:=ADR(stContent);
ulSize:=SIZEOF(stContent);
IF OP_TRIG.Q AND iStep=0 THEN
iStep := 1;
END_IF
CASE iStep OF
0:
IF bExecute=FALSE THEN
Done := FALSE;
ErrorCode := 0;
bError := FALSE;
END_IF
1:
hFile := SysFileOpen(szFileName, Mode, ADR(pRes)); //打开文件
IF (pRes<>0 OR hFile=SysFile.RTS_INVALID_HANDLE) THEN
bError := TRUE;
ELSE
iStep := 2;
END_IF
2:
iRet:=SysFileWrite(hFile, pbyBuffer, ulSize, ADR(pRes)); //内容写入文件
IF (iRet=0) THEN
SysFileClose(hFile);
bError := TRUE;
ELSE
iStep := 3;
END_IF
3:
pRes:=SysFileFlush(hFile); //缓存内容写入文件
IF (pRes=0) THEN
iStep := 4;
ELSE
SysFileClose(hFile);
bError := TRUE;
END_IF
4:
pRes:=SysFileClose(hFile); //关闭文件
IF pRes=0 THEN
Done := TRUE;
iStep := 0;
ELSE
bError := TRUE;
END_IF
END_CASE
//错误检查
IF bError THEN
iStep := 0;
ErrorCode := 1;
END_IF
注意:SysFile库的文件读写操作是不能被其它周期任务中断的。当需要读写的文件较大时,需要的时间会比较长。这时候需要把运行读写程序的任务周期调长,保证读写操作能够顺利完成。如果任务时间不够,可能会出现文件没有读完或者写完的情况。
四、结论
SysFile库实际上属于运行系统的文件操作函数,不管是操作方式还是参数定义都与C语言的对应函数类似,对C语言比较熟悉的朋友应该很容易上手。另外需要注意的是底层操作函数与平台相关性较大,比如读写时间与所使用的的控制器平台关系很大,最好是在自己使用的平台上做一些读写测试后设置合理的任务周期,避免出现文件读写不完整问题。
关于SysFile库读写大文件的问题,还有一种思路是把以上代码封装成功能块,在读或者写过程中把大文件拆分成尺寸较小的块,通过分步多次读写,每次进入读写流程时读或者写一块,直至所有内容读写完成。当然这个流程会复杂一些,嫌麻烦的还是直接用CAA File库来实现吧~~~^-^。
------------------
原创不易,感兴趣的多支持!