清明第二天,为了假期不这么放纵,现在又来更新一篇文件操作的文章,关于文件操作比较底层,这里我们就了解一下有关函数使用和一些基础概念即可,无需深究函数是如何实现。
文件的分类
相信文件大家都很清楚,对于电脑上我们都储存了许多地文件,但是文件还分两种类型,那分为哪两种呢?-------程序文件,数据文件。
程序文件
程序文件包括源程序文件(后缀为.c),目标⽂件(windows环境后缀为.obj),可执行程序(windows 环境后缀为.exe)。
数据文件
文件的内容不⼀定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或 者输出内容的文件。
那么今天我们重点要讲的是数据文件唔。
那么其实数据文件还是可以细分为,文本文件,和二进制文件
二进制文件:在内存中数据以二进制储存,如果不加转换就直接输出到外存那就是二进制文件。
注意:二进制文件我们不编译打开的话我们是看不懂的。
文本文件:就与二进制文件相反,将内存中的二进制数据转化,再储存那就是文本文件,文本文件我们是可以看的懂的。
流的概念
我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输入输出 操作各不相同,为了方便程序员对各种设备进行方便的操作,我们抽象出了流的概念,我们可以把流 想象成流淌着字符的河。 C程序针对文件、画面、键盘等的数据输⼊输出操作都是通过流操作的。 ⼀般情况下,我们要想向流里写数据,或者从流中读取数据,都是要打开流,然后操作。
大家可以把流当作一张银行卡,我们存钱时往里面塞钱,取钱也是从里面取,这就类似于我们对输入输出的需求,它是一个媒介,流也分种类,类似银行卡也有种类。
标准流
大家看到上面的描述是不是开始疑惑一个点了,既然我们输出和输入数据都需要打开流那自己在编程软件的时候没打开也可以打印和读取数据,这不是矛盾了嘛?别急下面一一到来。
stdin - 标准输⼊流,在大多数的环境中从键盘输入,scanf函数就是从标准输入流中读取数据。
stdout - 标准输出流,大多数的环境中输出至显示器界面,printf函数就是将信息输出到标准输出 流中。
stderr - 标准错误流,大多数环境中输出到显示器界面。
而在我们编译器中是默认打开这三个流的,所以我们使用printf,和scanf等函数时,是不需要我们自己打开这几个流的。这三个流的类型为 FILE*类型通常称为文件指针。
缓冲文件系统中,关键的概念是“⽂件类型指针”,简称“文件指针”。 每个被使用的⽂件都在内存中开辟了⼀个相应的文件信息区,用来存放文件的相关信息(如文件的名 字,文件状态及文件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系 统声明的,取名 FILE.
关于文件信息区我们取一个例子:
int main() { FILE* p1; FILE* p2; FILE* p3; return 0; }
如上我们定义了三个为文件指针,如果给他们赋值,他们就会指向三个不同文件信息区。如下图:
如上,文件指针可以间接找到文件。
文件的打开和关闭
这里我们需要了解两个函数
FILE * fopen ( const char * filename, const char * mode ); int fclose ( FILE * stream );
第一个为打开文件函数,第二个为关闭文件的函数,我们进行文件操作时都需要打开和关闭。这是几乎要绑定在一起的。
然后打开文件中mode为打开文件模式,下面就列出几个常用的打开模式。
有关文本文件
“r”(只读) 为了输⼊数据,打开⼀个已经存在的文本文件 ( 如果文本文件不存在则会出错)
“w”(只写) 为了输出数据,打开⼀个文本文件 ( 如果文本文件不存在则会创建这个文本文件)
“a”(追加) 向文本文件尾添加数据 (如果文本文件不存在则会创建这个文本文件)
有关二进制文件
“rb”(只读) 为了输⼊数据,打开⼀个已经存在的二进制文件 ( 如果二进制文件不存在则会出错)
“wb”(只写) 为了输出数据,打开⼀个二进制文件 ( 如果文本文件不存在则会创建这个二进制文件)
“ab”(追加) 向二进制文件尾添加数据 (如果文本文件不存在则会创建这个二进制文件)
接下来是一些读写函数:
函数 功能 适用于
fgetc 字符输入函数 所有输⼊流
fputc 字符输出函数 所有输出流
fgets 文本行输入函数 所有输⼊流
fputs 文本行输出函数 所有输出流
fscanf 格式化输入函数 所有输⼊流
fprintf 格式化输出函数 所有输出流
fread ⼆进制输入 文件
fwrite ⼆进制输出 文件
接下来就给大家试试其中几个函数和打开模式功能:
“r”只读打开模式和fgetc函数:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main() { FILE* p1=fopen("p1.txt","r");//以只读的方式打开文件 if (p1 == NULL) { perror("fopen:"); return ; } int ch =1; printf("该文本文件里面的内容为:"); while ((ch = fgetc(p1)) != EOF) { printf("%c", ch);//打印里面的内容 } printf("\n"); fclose(p1);//关闭文件 return 0; }
在运行代码时我们需要先创建一个文件夹和往文件夹里写点东西,如下:
我们先是打开文件,如果打开失败就打印错误信息,并结束程序,如果打开成功则继续运行下面的代码。
然后我们便开始读文件,while循环中每个读取到的文件的字符放到ch里,并打印出来。如下:
”w“打开模式和fputc函数 :
int main() { FILE* p2=fopen("p2.txt","w");//以只写的方式打开文件 if (p2 == NULL) { perror("fopen:"); return; } int ch =1; for(ch='a';ch<='z';ch++) { fputc(ch, p2); } printf("\n"); fclose(p2);//关闭文件 return 0; }
这里我没有创建p2这个文件夹,但是”w“的打开模式会为我们自动创建
运行过后就多了一个p2的文件夹了。
打开里面所编辑的正是我们所需打印的东西,24个英文字母。
剩下的fputs,fgets,和二进制文件操作也类似这种操作。fputs则是写字符串,fgets则是读字符串。二进制操作也是将文本文件变成二进制文件。我这里就不一一列举完出来了。这里再简单示例一个fgets函数吧。
int main() { FILE* p2=fopen("p2.txt","r");//以只读的方式打开文件 if (p2 == NULL) { perror("fopen:"); return; } char arr[24]; fgets(arr, 5,p2); printf("%s\n",arr); fclose(p2);//关闭文件 return 0; }
fgets(arr, 5,p2);
这里的fgets(arr, 5,p2);,表示读取到p2里的5个字符放到arr里去,但大家可能会疑惑,不是5个嘛,怎么只打印出四个,那是因为它会为‘\0’留一个位置,所以只读取4个字符。
今天的文章就到这里了。文章也是花了两天的零散时间写完的。
常常会回顾努力的自己,所以要给自己的努力留下足迹。
为今天努力的自己打个卡,留个痕迹吧