深入了解语言级别(C语言)文件操作的"读"与"写"
在学习前,我们先要知道在Linux下的一个原则:一切皆是文件
如何理解呢?举个外设的例子,比如键盘和显示器,这两个外设也可以其实本质上也是文件,通过与内存的交互来交换信息,而交互的过程其实就是"读"与"写"的过程。而键盘和显示器这两个文件是会默认被打开的。
所以想要理解读与写,也就是对文件操作,那就必须得从内存的角度去看待问题:
- 从“人”的角度看,人读书写字,这个过程其实就是,书通过文字来传达出信息,人读取信息后,并记录文字在纸上。人读书其实就是向人大脑进行的一个输入知识的过程,这个过程称为“读”,人记录信息文字在纸上,也就是人大脑向纸进行输出的过程,这个过程称为“写”。
- 从“内存”的角度看,以显示器和键盘这两个文字为例,键盘就好比书上的文字,内存读取键盘时,就相当于人读取信息的过程,相对于内存而言,这是一种输入,人通过键盘向内存传达信息,也就是内存输入信息的过程,也就是“读”。而内存向显示器上打印文字的过程,就好比人在纸上写字的过程,这是内存对外的一个输出过程,也就是“写”。
因此,从内存的角度来看问题的话,一切都简单起来了:
键盘无外乎就是一种“读”:对应C/C++就是:scanf,cin,是input:输入的过程
显示器无外乎就是一种“写”:对应C/C++就是:printf,cout,是output:输出的过程
这样我们再来看看:什么是文件呢?
狭义上的文件:普通磁盘文件。
广义上的文件:显示器,键盘,网卡,声卡,显卡,磁盘,几乎所有的外设,都可以称为文件!
语言级文件读写操作函数
学习完这个小知识,接下来就来看看文件读写操作的相关语言级别的函数:
功能 | 函数名 | 适用于 |
---|---|---|
字符输入函数 | fgetc | 所有输入流->读 |
字符输出函数 | fputc | 所有输出流->写 |
文本行输入函数 | fgets | 所有输入流->读 |
文本行输出函数 | fputs | 所有输出流->写 |
格式化输入函数 | fscanf | 所有输入流->读 |
格式化输出函数 | fprintf | 所有输出流->写 |
二进制输入 | fread | 文件 |
二进制输出 | fwrite | 文件 |
fgetc和fputc
fputc是一种写操作,属于输出流,能够向指定文件种写入一个char类型,可以理解成:char put file(字符放入文件),若失败则返回EOF
fgetc是一种读操作,属于输入流,能够读取指定文件的一个字符,若读取失败,则返回EOF
代码演示:
int main()
{
//以键盘显示器为例:
//键盘显示器是默认打开的文件,因此不用进行open和close操作
int ch=0;
while((ch=fgetc(stdin))!=EOF)
{
fputc(ch,stdout);
}
return 0;
}
fgets 和 fputs
fputs 和 fgets 类似于fputc 和 fgetc
fputs 是一种写操作,属于输出流,能够向指定文件种写入一个string类型,可以理解成:char put string(字符串放入文件,但不包括 ‘\0’ ),若失败则返回EOF
fgets 是一种读操作,属于输入流,能够读取指定文件中至多比size大小小1的字符串然后将他放入指定的buffer,若提前遇到EOF文件末尾或者 ‘\n’ 则读取提前终止,‘\n’ 也会被读入,读入完成后将自动填充 ‘\0’ 。若读取成功则返回s字符串,失败或者什么都没读取到则返回NULL
代码示例:
int main()
{
//以键盘显示器为例:
//键盘显示器是默认打开的文件,因此不用进行open和close操作
char buffer[64];
while((fgets(buffer,sizeof buffer,stdin)!=NULL))
{
fputs(buffer,stdout);
}
return 0;
}
fscanf 和 fprintf
fscanf 是一种 ”读” 操作,属于一种输入流,他可以向指定的文件中读取信息并放入格式化参数中, 但若读取的信息大于格式化参数的大小,则结果就不被定义,读取成功则返回读取的信息的数量,失败则返回EOF
fprintf 是一种 “写” 操作,属于一种输出流,他可以向指定文件中写入指定的格式化参数,写入成功则返回写入的char类型的数量但不包括 ’\0‘ ,如果失败则返回一个负值
他们两个的用法其实跟scanf和printf一致,只不过需要指定对应的文件流,而scanf和printf则默认第一个参数为stdin和stdout。
代码示例:
int main()
{
//以键盘显示器为例:
//键盘显示器是默认打开的文件,因此不用进行open和close操作
char s[20];
while(fscanf(stdin,"%s",&s)!=EOF)
fprintf(stdout,"%s\n",s);
return 0;
}
注意格式化的使用方法,遇到空格就代表一个占位符的读取已经读取完毕,若空格后还有单词且没有新的占位符就不会进行读入。
fwrite和fread
fwrite 是一种 “写” 操作,属于输出流,可以从内存中指定位置的数据中取出数据向指定文件中写入基本单位大小为size,个数为nmemb个size单位的数据(包括二进制数据),若写入成功则返回实际写入的基本单位的个数
fread 是一种 “读” 操作,属于输入流,可以从指定文件中读取基本单位大小为size,个数为nmemb个size单位的数据(包括二进制数据)放入被指向的内存位置中,若读取成功则返回实际读取的基本单位的个数
int main()
{
FILE* fp=fopen("log.txt","w");
if(fp==NULL)
{
perror("fopen");
}
const char* s1="hello fwrite\n";
fwrite(s1,strlen(s1),1,fp);
if(fwrite)
{
fwrite(s1,strlen(s1),1,stdout);
}
fclose(fp);
return 0;
}
";
fwrite(s1,strlen(s1),1,fp);
if(fwrite)
{
fwrite(s1,strlen(s1),1,stdout);
}
fclose(fp);
return 0;
}
[外链图片转存中...(img-GPl5d72L-1707560962937)]