摘要:例如为了方便起见,文件标识常被称为文件名。文件的打开和关闭文件指针缓冲文件系统中,关键的概念是文件类型指针,简称文件指针。文本文件和二进制文件根据数据的组织形式,数据文件被称为文本文件或者二进制文件。
●?个人主页:你帅你先说.
●?欢迎点赞?关注?收藏?
●?既选择了远方,便只顾风雨兼程。
●?欢迎大家有问题随时私信我!
●?版权:本文由[你帅你先说.]原创,CSDN首发,侵权必究。
磁盘上的文件是文件。
但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境
后缀为.exe)。
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文
件,或者输出内容的文件。
一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀。
例如:c:/code/test.txt
为了方便起见,文件标识常被称为文件名。
缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名
字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE。
例如,VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明:
struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; };typedef struct _iobuf FILE;
不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。
每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。
一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
下面我们可以创建一个FILE*的指针变量:
FILE* pf;//文件指针变量
定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变
量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。
ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。
//打开文件FILE * fopen ( const char * filename, const char * mode );//关闭文件int fclose ( FILE * stream);
filename
是文件名,mode
是打开方式,stream
是文件指针。
打开方式
fopen和fclose的使用
int main(){ //打开文件 FILE* pf = fopen("C://Users//LJT//Desktop//Date.txt", "r"); //要注意转义字符,//防止被转义。 if (pf == NULL) { perror("fopen");//若出错了则输出错误码 return -1; } //读文件 // //关闭文件 fclose(pf); pf = NULL; return 0;}
这些是对文件进行读写操作的函数。
这些函数怎么用呢?
int main(){ FILE* pf = fopen("C://Users//LJT//Desktop//Date.txt", "w"); if (NULL == pf) { perror("fopen"); return -1; } //写文件 fputc("h", pf); fputc("e", pf); fputc("l", pf); fputc("l", pf); fputc("o", pf); //关闭文件 fclose(pf); pf = NULL; return 0;}
这个时候打开文件你就会发现hello
被写入了。
int main(){ FILE* pf = fopen("C://Users//LJT//Desktop//Date.txt", "r"); if (NULL == pf) { perror("fopen"); return -1; } //读文件 int ch = fgetc(pf); //刚刚文件中输出了hello //所以现在用fgetc输入前三个字符屏幕上会出现hel printf("%c/n", ch);//h ch = fgetc(pf); printf("%c/n", ch);//e ch = fgetc(pf); printf("%c/n", ch);//l //关闭文件 fclose(pf); pf = NULL; return 0;}
int main(){ FILE* pf = fopen("C://Users//LJT//Desktop//Date.txt", "w"); if (NULL == pf) { perror("fopen"); return -1; } //写文件 //写一行数据 fputs("hello world/n", pf); fputs("hello China/n", pf); //关闭文件 fclose(pf); pf = NULL;}
运行结果
int main(){ FILE* pf = fopen("C://Users//LJT//Desktop//Date.txt", "r"); if (NULL == pf) { perror("fopen"); return -1; } //读文件 //读一行数据 char arr[20] = { 0 }; fgets(arr, 20, pf); printf("%s/n", arr); fgets(arr, 20, pf); printf("%s/n", arr); //关闭文件 fclose(pf); pf = NULL;}
?:fgets
函数的第二个参数指的是最大的容量,实际上最后一个位置为留给’/0’,例如容量为5,你输入hello,实际上只输入了hell,结尾会添上一个’/0’,fgets
函数是一行一行读写的,不会跨行读写。
struct S{ int n; double d;};int main(){ struct S s = { 100, 3.14 }; FILE* pf = fopen("C://Users//LJT//Desktop//Date.txt","w"); if (NULL == pf) { perror("fopen"); return -1; } //写文件 fprintf(pf, "%d %lf", s.n, s.d); //关闭文件 fclose(pf); pf = NULL;}
运行结果
struct S{ int n; double d;};int main(){ struct S s = {0}; FILE* pf = fopen("C://Users//LJT//Desktop//Date.txt", "r"); if (NULL == pf) { perror("fopen"); return -1; } //读文件 fscanf(pf, "%d %lf", &(s.n), &(s.d)); printf("%d %lf/n", s.n, s.d); //关闭文件 fclose(pf); pf = NULL;}
运行结果
接下来的函数与其它函数不同,它们是以二进制的形式写入输出的。
struct S{ int n; double d; char name[10];};int main(){ struct S s = {100, 3.14, "zhangsan"}; FILE* pf = fopen("C://Users//LJT//Desktop//Date.txt", "wb"); if (NULL == pf) { perror("fopen"); return -1; } //写文件 - 二进制的方式写 fwrite(&s, sizeof(s), 1, pf); //关闭文件 fclose(pf); pf = NULL;}
运行结果
这个时候你会发现出现了一些诡异的东西。难道是输错了吗?并没有,因为我们是以二进制的形式写入的,所以是这样的,但不代表是错的,我们可以将它输出验证是否正确。
struct S{ int n; double d; char name[10];};int main(){ struct S s = {0}; FILE* pf = fopen("C://Users//LJT//Desktop//Date.txt", "rb"); if (NULL == pf) { perror("fopen"); return -1; } //读文件 - 二进制的方式读 fread(&s, sizeof(struct S), 1, pf); //打印 printf("%d %lf %s/n", s.n, s.d, s.name); //100 3.140000 zhangsan //关闭文件 fclose(pf); pf = NULL;}
运行结果
sprintf
函数
int main(){ char arr[100] = { 0 }; struct S s = { 100, 3.14, "zhangsan" }; //把一个格式化的数据转换成字符串 sprintf(arr, "%d %lf %s", s.n, s.d, s.name); //打印 printf("%s/n", arr); return 0;}
输出结果
sscanf
函数
struct S{ int n; double d; char name[10];};int main(){ char arr[100] = { 0 }; struct S tmp = { 0 }; struct S s = { 100, 3.14, "zhangsan" }; //把一个格式化的数据转换成字符串 sprintf(arr, "%d %lf %s", s.n, s.d, s.name); //打印 printf("%s/n", arr); //从arr中的字符串中提取出一个格式化的数据 sscanf(arr, "%d %lf %s", &(tmp.n), &(tmp.d), tmp.name); //打印 printf("%d %lf %s/n", tmp.n, tmp.d, tmp.name); return 0;}
两次结果一样说明读取成功。
输入输出函数的对比
scanf
从标准输入流(键盘)读取格式化的数据
fscanf
从所有的输入流读取格式化的数据
sscanf
从字符串中读取一个格式化的数据
printf
把格式化的数据输出到标准输出(屏幕)上
fprintf
把格式化的数据输出到所有输出流(屏幕/文件)上
sprintf
把格式化的数据转换成对应的字符串!
函数参数
int fseek ( FILE * stream, long int offset, int origin );
第一个函数是文件指针,第二个参数是偏移量,第三个参数则是起始位置。
orgin
可以传三种参数
翻译过来就是
当前文件指针所指向的位置
文件的结尾
文件的开始
怎么用呢?举个?:
#include int main(){ //1. 打开文件 FILE* pf = fopen("data.txt", "r"); if (NULL == pf) { perror("fopen"); return -1; } //2. 读文件,假设此时文件中已写入abcde //第一次就要读取"c" fseek(pf, 2, SEEK_SET);//从开始位置读写 int ch = fgetc(pf);//读的是c printf("%c/n", ch); fseek(pf, -2, SEEK_CUR);//从文件指针位置开始读写 ch = fgetc(pf);//读的是b //可能有人会疑惑倒退两个读的不是a吗怎么是b,因为当你第一个读完c后你的文件指针已经指向了d,所以倒退两个读的是b printf("%c/n", ch); //3. 关闭文件 fclose(pf); pf = NULL; return 0;}
函数参数
long int ftell ( FILE * stream );
这个函数是用来返回文件指针相对于起始位置的偏移量。
这个函数用起来很简单,不做过多介绍。
函数参数
void rewind ( FILE * stream );
这个函数是让文件指针的位置回到文件的起始位置的。
根据数据的组织形式,数据文件被称为文本文件或者二进制文件。
数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。
一个数据在内存中是怎么存储的呢?
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2013测试)。
举个?:
int main(){ //1. 打开文件 FILE* pf = fopen("data.txt", "wb"); if (NULL == pf) { perror("fopen"); return -1; } int a = 10000; //以2进制的形式写文件 fwrite(&a, 4, 1, pf); //3. 关闭文件 fclose(pf); pf = NULL; return 0;}
这个时候你打开文本文件你会发现你看不懂,但没关系,将这个文本文件从vs中打开
这个时候显示的就是10000以二进制形式存储以十六进制的形式显示了。
被错误使用的feof
牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。
1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
例如:
fgetc 判断是否为 EOF .
fgets 判断返回值是否为 NULL .
2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数。
文本文件的例子:
#include #include int main() { int c; // 注意:int,非char,要求处理EOF FILE* fp = fopen("test.txt", "r"); if(!fp) { perror("File opening failed"); return EXIT_FAILURE; } //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环 { putchar(c); }//判断是什么原因结束的 if (ferror(fp)) puts("I/O error when reading");//I/O错误 else if (feof(fp)) puts("End of file reached successfully");//遇到文件尾结束 fclose(fp);}
二进制文件的例子:
#include enum{
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/121799.html
摘要:前提最近我的的朋友浏览一些网站,看到好看的图片,问我有没有办法不用手动一张一张保存图片我说用丫保存壁纸太麻烦教你如何用快速获取网站图片项目 前提最近我的的朋友浏览一些网站,看到好看的图片,问我有没有办法不用手动一张一张保存图片!我说用Jsoup丫!打开开发者模式(F12),找到对应图片的链接,在互联网中,每一张图片就是一个...
摘要:格式化安装插件如果题主认真读了的的话,应该可以写出下面的配置了。用来格式化和提示格式错误。在编码过程中提示格式错误,养成良好的编码习惯。 前言 感觉搭建一个舒服的前端开发环境,十分的重要定制化的格式化,编辑器自带的格式化各种报错,手动改真的会死人,因此搭建一个编辑器环境必不可少,现在要讲的是vscode中如何定制vue vs code的配置文件: showImg(https://seg...
摘要:上一篇文章手把手教你如何用构建技术文章聚合平台一介绍了如何使用搭建的运行环境,并且将与集成,对掘金进行技术文章的抓取,最后可以查看抓取结果。本篇文章将继续讲解如何利用编写一个精简的聚合平台,将抓取好的文章内容展示出来。 上一篇文章《手把手教你如何用Crawlab构建技术文章聚合平台(一)》介绍了如何使用搭建Crawlab的运行环境,并且将Puppeteer与Crawlab集成,对掘金、...
摘要:成果展示先来看看成果,原图为文章开始的图片,一图切九图朋友圈九张图发朋友圈的时候,还有个比较有意思的事,上传时是乱序的,还需要你自己像玩拼图一样自己摆位置。这下又可以在朋友圈秀操作了比如改改背景呀,黑色背景什么的。 showImg(https://segmentfault.com/img/remote/1460000019609677); 01 前言 在日常的生活中,大家偶尔会看到朋友...
摘要:所以现在我们就用来写一个的转模型的库吧。所以我们首先要解决的问题是如何在将字典转成模型。表示的是属性的值。如果你看看我们转模型的方法定义就能明白了。写在最后通过上面的几个步骤,我们就能很快的实现一个简单的转模型的需求了。 在iOS项目开发过程中,我们经常会用到将从服务器获取的 json 转 model 的操作,我们可以使用 Swift 提供的setValuesForKeys 或者 Ob...
阅读 458·2021-11-18 13:12
阅读 1391·2021-11-16 11:42
阅读 1071·2021-11-15 11:39
阅读 3327·2021-10-09 09:44
阅读 1302·2021-10-08 10:04
阅读 2325·2021-09-23 11:22
阅读 5786·2021-09-22 15:15
阅读 3438·2021-09-02 09:54