前言
在前面的文章中,我们已经对文件IO进行了简单的介绍。今天,我们便对另外一种IO操作相关的函数—标准IO进行初步的学习。
fopen函数
作用
与文件IO中的open函数的作用一致,fopen函数的作用也是打开一个文件。只是在形式上有所不同。
函数形式
函数原型 | FILE *fopen(const char *path, const char *mode) |
---|---|
头文件 | #include <stdio.h> |
参数含义 | 如下 |
返回值 | 成功:返回一个文件流指针 失败:返回NULL值 |
其中,参数path指的是需要打开文件的路径和文件的文件名,而参数mode则指的是以什么方式打开该文件,可选的值为:
"r":以只读的方式打开文件
"r+":以读写的方式打开文件
"w":以覆盖的方式打开文件或者创建一个文件指针指向文件开头的可写的新文件
"w+":以覆盖的读写方式打开文件或者创建一个文件指针指向文件开头的新文件
"a":以追加的方式打开文件(不会覆盖文件之前的内容)或者创建一个文件指针指向文件末尾的新文件
"a+":以追加的方式打开文件或者创建一个新的文件,当读取文件的内容时,文件指针将指向文件开头,但是写入内容时,文件指针将指向文件的结尾
文件的权限问题
与open函数不同,fopen函数在创建一个新文件时,并没有提供指定文件权限的参数。所以,利用fopen函数创建的新文件的权限是默认的,为0666与取反后的文件掩码相与的结果。比如:当文件掩码为0222时,那么利用fopen函数创建的文件权限为:0666&(~0222) = 0444
当然,如果后续需要更改文件的权限,我们可以利用chmod等命令进行相应的更改。
测例
利用fopen函数,以追加的方式新建一个文件:
#include <stdio.h>
int main(int argc,char* argv[])
{
FILE* pd;
pd = fopen(argv[1],"a+");
if(NULL == pd)
{
printf("open file %s failed!\n",argv[1]);
}
fclose(pd);
return 0;
}
fclose函数
作用
fclose函数的作用与文件IO中的close函数的作用是一致的,作用都是关闭打开的文件,只是两者的形式不同。
函数原型
函数原型 | int fclose(FILE *fp) |
---|---|
头文件 | #include <stdio.h> |
参数含义 | 如下 |
返回值 | 成功:返回0 失败:返回-1 |
其中,参数fp即利用fopen函数返回的文件流指针。
与文件IO操作类似,当利用fopen函数打开一个文件之后,一定要在相应的位置利用fclose函数关闭该文件。
fseek函数和rewind函数
作用
与文件IO函数类似,标准IO也存在文件指针的概念。所以,在实际应用中,当用户想要指定操作的文件指针的位置时,便需要使用fseek函数或者rewind函数,对文件指针的位置进行更改。
rewind函数原型
rewind函数的作用是将文件指针的位置调整到文件的开头处,其函数原型如下:
函数原型 | void rewind(FILE *stream) |
---|---|
头文件 | #include <stdio.h> |
参数 | 如下 |
返回值 | 无返回值 |
其中,参数stream即利用fopen函数打开文件时返回的文件流指针。
fseek函数原型
对于标准IO操作而言,不仅可以使用rewind函数将文件指针的位置调整到文件的开头,同样也可以使用fseek函数,调整文件指针的位置到其他地方。该函数的原型如下:
函数原型 | int fseek(FILE *stream, long offset, int whence) |
---|---|
头文件 | <stdio.h> |
参数 | 如下 |
返回值 | 成功:返回文件指针的位置 失败:返回-1 |
其中,参数stream即上述的文件流指针,参数whence即以什么地址为基准进行文件指针的调整,可选的参数为:
SEEK_SET:文件开头
SEEK_CUR://当前位置
SEEK_END://文件结尾
参数offset指的便是文件指针的偏移值,正数意味着向右进行偏移,负数则意味着向左进行偏移。
比如:
rewind(pd);//将文件指针调整到文件开头
fseek(pd,-2,SEEK_END);//将文件指针的位置调整到文件的倒数第二个位置处
fseek(pd,0,SEEK_SET);//将文件指针的位置调整到文件的开头处
有上述可知,rewind(pd)函数与fseek(pd,0,SEEK_SET)函数是等价的。
ftell函数
ftell函数的作用是获取文件当前文件指针的位置。
函数原型如下:
函数原型 | long ftell(FILE *stream) |
---|---|
头文件 | <stdio.h> |
参数 | 如下 |
返回值 | 成功:返回文件指针的位置 失败:返回-1 |
其中,参数stream同样指的是文件流指针。
fflush函数
无论是行缓存函数还是全缓存函数,当使用fflush刷新缓存时,均会强制将缓存中的内容写到内核的缓存中。
标准IO中的读写函数
在标准IO操作中,读写函数比较多,我们首先按照之前提到的缓存特性,对标准IO中的读写函数进行分类。
按照缓存的特性,我们可以将标准IO中的读写函数分为:
1、行缓存读写函数:
读函数:
fgets gets printf fprintf sprintf
写函数:
fputs puts scanf
2、全缓存读写函数:
读函数:
fread
写函数:
fwrite
3、无缓存读写函数:
stderr
由于标准IO函数中的读写函数较多,所以此处就不进行一一讲解了,而对在使用过程中需要注意的地方进行简单的总结:
1、fprintf、printf和sprintf函数之间的区别?
①fprintf函数可以将内容输出到一个文件或者标准输出上(一般为屏幕)
②printf函数只能将内容输出到标准输出上
③sprintf函数是将内容复制给一个字符串
feof函数和ferror函数
在利用上述的读函数读取文件中的内容时,当读取到文件结尾或者读取文件失败时,读函数均会返回EOF。那么,在实际应用中,怎样判断到底是已经读取到了文件结尾,还是读取文件时发生了错误呢?我们可以利用feof函数或者ferror函数进行判断。feof函数的原型如下:
函数原型 | int feof(FILE *stream) |
---|---|
头文件 | <stdio.h> |
参数 | 如下 |
返回值 | 返回非零值:已经到了文件结尾 返回零值:并没有到达文件结尾 |
其中,参数stream仍然是上述的文件流指针。
ferror函数的原型如下:
函数原型 | int ferror(FILE *stream) |
---|---|
头文件 | <stdio.h> |
参数 | 如下 |
返回值 | 返回非零值:读写文件失败 返回零值:成功读写文件 |
其中,参数stream仍然是文件流指针。
综合测例
利用上面的标准IO函数或者相应的库函数,实现cat命令:
cat命令的作用是显示一个文件中的内容:
#include <stdio.h>
#include <string.h>
int main(int argc,char* argv[])
{
FILE* pd;
char* write_buf = "Hello Linux";
char read_buf[128] = {0};
ssize_t write_num = 0,read_num = 0;
pd = fopen(argv[1],"r");
if(NULL == pd)
{
printf("open file %s failed!\n",argv[1]);
return -1;
}
//write_num = fwrite(write_buf,sizeof(write_buf[0]),strlen(write_buf),pd);
rewind(pd);
while(1)
{
read_num = fread(read_buf,sizeof(read_buf[0]),128,pd);
printf("%s",read_buf);
if(read_num < 128)
{
break;
}
}
printf("\n");
fclose(pd);
}