文件操作.md
一、源代码说明
freecplus是一个Linux系统下的C/C++开源框架,源代码请前往C语言技术网(www.freecplus.net)下载。
本文介绍的是freecplus框架的文件操作的函数和类。
函数和类的声明文件是freecplus/_freecplus.h。
函数和类的定义文件是freecplus/_freecplus.cpp。
示例程序位于freecplus/demo目录中。
编译规则文件是freecplus/demo/makefile。
二、文件操作函数
1、删除文件
删除目录中的文件,类似Linux系统的rm命令。
函数声明:
1 | bool REMOVE(const char *filename,const int times=1); |
参数说明:
filename:待删除的文件名,建议采用绝对路径的文件名,例如/tmp/root/data.xml。
times:执行删除文件的次数,缺省是1,建议不要超过3,从实际应用的经验看来,如果删除文件第1次不成功,再尝试2次是可以的,更多次就意义不大了。还有,如果执行删除失败,usleep(100000)后再重试。
返回值:true-删除成功;false-删除失败,失败的主要原因是权限不足。
在应用开发中,可以用REMOVE函数代替remove库函数。
2、文件重命名
把文件重命名,类似Linux系统的mv命令。
函数声明:
1 | bool RENAME(const char *srcfilename,const char *dstfilename,const int times=1); |
参数说明:
srcfilename:原文件名,建议采用绝对路径的文件名。
destfilename:目标文件名,建议采用绝对路径的文件名。
times:执行重命名文件的次数,缺省是1,建议不要超过3,从实际应用的经验看来,如果重命名文件第1次不成功,再尝试2次是可以的,更多次就意义不大了。还有,如果执行重命名失败,usleep(100000)后再重试。
返回值:true-重命名成功;false-重命名失败,失败的主要原因是权限不足或磁盘空间不够,如果原文件和目标文件不在同一个磁盘分区,重命名也可能失败。
注意,在重命名文件之前,会自动创建destfilename参数中的目录名。
在应用开发中,可以用RENAME函数代替rename库函数。
3、复制文件
复制文件,类似Linux系统的cp命令。
函数声明:
1 | bool COPY(const char *srcfilename,const char *dstfilename); |
参数说明:
srcfilename:原文件名,建议采用绝对路径的文件名。
destfilename:目标文件名,建议采用绝对路径的文件名。
返回值:true-复制成功;false-复制失败,失败的主要原因是权限不足或磁盘空间不够。
注意:
1)在复制名文件之前,会自动创建destfilename参数中的目录名。
2)复制文件的过程中,采用临时文件命名的方法,复制完成后再改名为destfilename,避免中间状态的文件被读取。
3)复制后的文件的时间与原文件相同,这一点与Linux系统cp命令不同。
4、获取文件的大小
函数声明:
1 | int FileSize(const char *filename); |
参数说明:
filename:待获取的文件名,建议采用绝对路径的文件名。
返回值:如果文件不存在或没有访问权限,返回-1,成功返回文件的大小,单位是字节。
5、获取文件的时间
函数声明:
1 | bool FileMTime(const char *filename,char *mtime,const char *fmt=0); |
参数说明:
filename:待获取的文件名,建议采用绝对路径的文件名。
mtime:用于存放文件的时间,即stat结构体的st_mtime。
fmt:设置时间的输出格式,与LocalTime函数相同,但缺省是"yyyymmddhh24miss"。
返回值:如果文件不存在或没有访问权限,返回false,成功返回true。
6、重置文件的时间
函数声明:
1 | int UTime(const char *filename,const char *mtime); |
参数说明:
filename:待重置的文件名,建议采用绝对路径的文件名。
stime:字符串表示的时间,格式不限,但一定要包括yyyymmddhh24miss,一个都不能少。
返回值:true-成功;false-失败,失败的原因保存在errno中。
7、示例程序
示例(demo34.cpp)
1 | /* |
三、文件读取函数
1、打开文件
函数声明:
1 | FILE *FOPEN(const char *filename,const char *mode); |
参数说明:
FOPEN函数调用fopen库函数打开文件,如果文件名中包含的目录不存在,就创建目录。
FOPEN函数的参数和返回值与fopen函数完全相同。
在应用开发中,用FOPEN函数代替fopen库函数。
2、读取文件
从文本文件中读取一行。
函数声明:
1 | bool FGETS(const FILE *fp,char *buffer,const int readsize,const char *endbz=0); |
参数说明:
fp:已打开的文件指针。
buffer:用于存放读取的内容。
readsize:本次打算读取的字节数,如果已经读取到了结束标志,函数返回。
endbz:行内容结束的标志,缺省为空,表示行内容以"\n"为结束标志。
返回值:true-成功;false-失败,一般情况下,失败可以认为是文件已结束。
3、示例程序
示例(demo36.cpp)
1 | /* |
demo36.cpp程序生成了数据文件/tmp/aaa/bbb/ccc/tmp.xml,数据内容如下:
以上数据文件只有两条有效的记录,但是第二条数据是跨多行的,在memo标签里,文字和换行符都是内容的一部分。
示例(demo37.cpp)
1 | /* |
运行效果
第二条记录的内容不完整,这并不是程序员想要的结果,如果demo37.cpp启用以下代码:
1 | if (FGETS(fp,strBuffer,300,"<endl/>")==false) break; // 行内容以"<endl/>"结束。 |
运行效果
这才是程序员想要的结果。
四、CFile类
CFile类根据实际开发中的应用场景,对常用的文件操作功能做了封装。
我们来先介绍类的声明,然后再列出常用应用场景的示例。
1、类的声明
1 | // 文件操作类声明 |
2、应用场景示例
在CFile类中,每个成员变量和函数都很容易理解,但不一定能准确的用于应用开发的场景中,我现在列出两个常用的场景。
场景一:某程序每隔若干时间就会产生一批数据,并把这些数据写入文件中。
程序的流程如下:
1)创建数据文件;
2)往文件中写入数据;
3)关闭数据文件。
如果程序这么写,得0分,因为这个流程存在一个严重的问题,那就是在第2)步往文件中写入数据需要时间,从创建文件到写入完成之前,这个文件的内容是不完整的,如果这个不完整的文件被其它程序读取了,怎么办?给文件加锁?用标志位区分?太麻烦。
假设待写入的数据文件名是/tmp/data/surfdata_20200101123000.txt,修改后的程序流程如下:
1)创建文件/tmp/data/surfdata_20200101123000.txt.tmp;
2)往文件中写入数据;
3)关闭数据文件;
4)把文件/tmp/data/surfdata_20200101123000.txt.tmp重命名为/tmp/data/surfdata_20200101123000.txt。
示例(demo39.cpp)
1 | /* |
每运行一次demo39程序,就会在/tmp/data目录下生成一个数据文件,如下:
场景二:从目录中读取场景一生成的数据文件,解析处理后保存到数据库中,然后删除目录中的文件。
我们利用demo39程序生成的数据来测试。
示例(demo40.cpp)
1 | /* |
运行效果
五、版权声明
C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。
来源:C语言技术网(www.freecplus.net)
作者:码农有道