每种语言都有对文件操作的相关功能。但我们知道,文件是存储在硬盘中的,而程序是运行在内存中的,要让程序在内存中运行的时候去操作硬盘中的文件,靠的其实是计算机底层的一些东西。在计算机底层,向上暴露出了一些功能接口,开发人员就可以通过这些接口来更好地操作计算机。
有很多用c开发的项目,用的文件操作是一些经过封装好的第三方工具,但其实呢,C语言本身也有对文件进行操作的函数,接下来就一起来了解一下:
要了解对文件操作的一些函数,那我们首先要知道什么叫文件,
一般呢,磁盘上的文件,都是文件,但是呢对于程序设计而言,我们说的文件有两种:一种是程序文件,另一种是数据文件。我们要用程序去操作的就是数据文件。接下来我们就去看一下,怎么操作一个文件。
fopen()
FILE *fopen( const char *filename, const char *mode );
int fclose( FILE *stream );
首先,要操作做一个文件,那第一步,就是打开这个文件,也就是下面要说的 fopen() 函数。
这个函数有两个参数,第一个参数是这个文件的文件名,第二个参数是打开文件的方式,
例如:
FILE * pf1 = fopen("test1.txt", "r");
FILE * pf2 = fopen("D:\\test2.txt", "w");
先不用管这个函数的返回值,先说一下函数的两个参数,
两行代码对比一下,第一个函数要打开的文件名没有带路径,那就是说,要打开的文件和项目在同一个目录下,而第二个函数要打开的文件,是带盘符的绝对路径,那打开的就是指定路径下对应的文件。且第一个函数的打开方式是 "r" ,代表以只读的方式打开,第二个函数的打开方式是 "w" ,那就是一只写的方式打开。下面列举一些不同的打开文件的方式:
文件使用方式 | 含义 | 如果指定文件不存在 |
"r"(只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
"w"(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
“a”(追加) | 向文本文件尾添加数据 | 出错 |
“rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb”(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
“ab”(追加) | 向一个二进制文件尾添加数据 | 出错 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+”(读写) | 为了读和写,建议一个新的文件 | 建立一个新的文件 |
“a+”(读写) | 打开一个文件,在文件尾进行读写 | 建立一个新的文件 |
“rb+”(读写) | 为了读和写打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,新建一个新的二进制文件 | 建立一个新的文件 |
“ab+”(读写) | 打开一个二进制文件,在文件尾进行读和写 | 建立一个新的文件 |
然后就是fopen函数的返回值:
FILE 是一个文件指针。什么是文件指针呢,在通过fopen打开一个文件的时候,每个被打开的文件都会在内存中开辟一片空间,用来存放文件的相关信息(如文件的名字,文件状态,以及文件的位置等)这些信息是保存在一个结构体变量中的,改结构体是有系统声明的,取名FILE
在vs2008的编译提供的头文件stdio.h中有以下的文件类型声明
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
fopen在调用后的返回值指向要操作的文件在内存中的结构体变量的位置,通过这个指针就可以操作文件了
fclose()
fclose这个函数是用来关闭打开文件时候的这个流的,因为流在一个系统中,是有限的资源,不释放的话,会严重影响系统的运行,使用方法也很简单,就是将打开文件是接收到的文件结构体指针传给fclose函数:
fclose(pf);
文件的顺序读写:
功能 | 函数名 | 适用于 |
字符输入函数 | fgetc | 所有输入流 |
字符输出函数 | fputc | 所有输出流 |
文本行输入函数 | fgets | 所有输入流 |
文本行输出函数 | fputs | 所有输出流 |
格式化输出函数 | fscanf | 所有输出流 |
格式化输入函数 | fprintf | 所有输入流 |
二进制输出 | fwrite | 文件 |
二进制输入 | fread | 文件 |
注意:平时我们说的输入输出是对于终端而言的,但是对于文件操作的输入输出,相对的是内存和硬盘之间的交互,因为程序运行在内存中,所以从内存到硬盘叫输出,从硬盘到内存是输入。
文件的随机读写
fseek()函数
int fseek ( FILE * stream, long int offset, int origin );
根据指针的位置和偏移量来定位文件指针,其中第一个参数是要操作的文件指针,第二个参数是偏移量,第三个参数是相对于什么位置,
SEEK_CUR 相对于现在的指针位置来定位
SEEK_END 相对于文件结尾来定位--此时offset参数应为负数,也就是相对于文件结尾前的多少字符
SEEK_SET 相对于文件开头来定位--此时offset应为正数,相对于文件开头后的几个字符
ftell():long int ftell ( FILE * stream );
ftell函数可以返回这个文件指针相对于起始位置的偏移量。
rewind():void rewind ( FILE * stream );
这个函数可以让这个文件指针回到起始位置。
关于文件是否读取结束
在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。
1. 文本文件读取是否结束,判断返回值是否为EOF (fgetc),或者NULL(fgets)
例如:
fgetc判断是否为EOF.
fgets判断返回值是否为NULL.
2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数。