360建站平台,个人域名备案需要什么,1688官网登录账号,秦皇岛网站公司文章目录 一、什么是文件1.程序文件2.数据文件 二、数据文件1.文件名2.数据文件的分类文本文件二进制文件 三、文件的打开和关闭1.流和标准流流标准流 2.文件指针3.文件的打开和关闭文件的打开文件的关闭 四、文件的顺序读写1.fgetc函数2.fputc函数3.fgets函数4.fputs函数5.fsc… 文章目录 一、什么是文件1.程序文件2.数据文件 二、数据文件1.文件名2.数据文件的分类文本文件二进制文件 三、文件的打开和关闭1.流和标准流流标准流 2.文件指针3.文件的打开和关闭文件的打开文件的关闭 四、文件的顺序读写1.fgetc函数2.fputc函数3.fgets函数4.fputs函数5.fscanf函数6.fprintf函数7.fwrite函数8.fread函数 一、什么是文件 我们写的程序的数据是存储在电脑的内存中如果程序退出内存回收数据就丢失了等再次运⾏程序是看不到上次程序的数据的如果要将数据进⾏持久化的保存我们可以使⽤⽂件 文件是计算机系统中的一个基本概念它是存储在计算机上的信息集合可以是文本文档、图片、程序等但是在程序设计中我们⼀般谈的⽂件有两种程序⽂件、数据⽂件从⽂件功能的⻆度来分类的
1.程序文件 程序⽂件包括源程序⽂件后缀为.c,⽬标⽂件windows环境后缀为.obj,可执⾏程序windows环境后缀为.exe
2.数据文件 文件的内容不⼀定是程序而是程序运行时读写的数据比如程序运⾏需要从中读取数据的⽂件或者输出内容的⽂件
二、数据文件 本文着重讨论的是数据文件在以前我们学的知识中所处理的数据的输⼊都是以键盘输⼊数据用显示器输出 但是我们之前的程序结果输出到显示器后结束程序这个结果不会被保存那是因为我们运行程序时把数据放在了内存程序结束后内存回收了数据也就没了 那我们很多情况下想把数据永久保存起来就要使用磁盘上的数据文件存储起来存储到磁盘的数据就会一直保存当需要使用数据时就从数据文件中将数据读入到我们的内存进行操作本文将会讲解的就是操作数据文件
1.文件名 ⼀个⽂件要有⼀个唯⼀的⽂件标识以便⽤⼾识别和引⽤这个文件标识就是我们常说的文件名⽂件名包含3部分⽂件路径⽂件名主⼲⽂件后缀
例如 c:\code\test.txt在这个例子中文件的路径就是c:\code\文件名的主干就是test文件后缀是.txt说明这个文件是一个文本文件属于数据文件之一 而路径又可以分为相对路径和绝对路径上面演示的就是绝对路径如果对这个有兴趣的话可以自行搜索文章学习这里我们还是继续进行我们的文件操作的学习
2.数据文件的分类 根据数据的组织形式数据⽂件被称为⽂本⽂件或者⼆进制⽂件
文本文件 如果要求在外存上以ASCII码的形式存储则需要在存储前转换以ASCII字符的形式存储的⽂件就是⽂本⽂件 简单的理解就是如果打开这个文件你可以看懂上面的信息那么就是文本文件例如汉字英文字母等等信息文本文件常见的后缀为.txt 和 .docx 以及 .rtf
二进制文件 数据在内存中以⼆进制的形式存储如果不加转换的输出到外存的⽂件中就是⼆进制⽂件由于里面是0和1序列组成的二进制然后转换出来的字符所以根本看不懂里面的内容 我们可以在VS运行下面的代码如果不懂也没有关系后面会讲到这里只是举一个例子
#define _CRT_SECURE_NO_WARNINGS#include stdio.h
int main()
{int a 10000;//以二进制写的方式打开FILE* pf fopen(test.txt, wb);if (pf NULL){perror(fopen);return 1;}//⼆进制的形式写到⽂件中fwrite(a, 4, 1, pf);//关闭文件fclose(pf);pf NULL;return 0;
}我们运行它之后会发现当前代码路径下会多出一个test.txt的文件打开当前代码路径的方法是单击左上角文件夹图标如图 然后我们双击打开这个文件 可以看到我们明明是将10000写入到了这个文件中但是最后我们打开文件后发现是一个我们看不懂的字符原因就是我们写入时是以二进制的写入方式打开文件的里面存储的是二进制的信息
三、文件的打开和关闭
1.流和标准流
流 我们程序的数据需要输出到各种外部设备也需要从外部设备获取数据不同的外部设备的输⼊输出操作各不相同为了⽅便程序员对各种设备进行方便的操作我们抽象出了流的概念我们可以把流想象成流淌着字符的河 比如向文件里输入信息和向屏幕输入信息的方式不同但是程序员不必了解它们如何输入的程序员只需要去往对应的流写入或读出操作不需要担心各种设备的输入输出操作 ⼀般情况下我们要想向流⾥写数据或者从流中读取数据都是要打开流然后操作打开流的方法我们后面会讲到
标准流 刚刚提到了如果要输入或者读取信息都要打开流然后进行操作那么每次我们在键盘输入信息在屏幕上打印信息为什么没有专门打开流呢那是因为C语言程序在启动时默认打开了3个标准流
stdin - 标准输⼊流在⼤多数的环境中从键盘输⼊scanf函数就是从标准输⼊流中读取数据stdout - 标准输出流⼤多数的环境中输出⾄显⽰器界⾯printf函数就是将信息输出到标准输出流中stderr - 标准错误流⼤多数环境中输出到显⽰器界⾯ 这是默认打开的三个标准流我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的它们的类型是FILE*的指针通常称为文件指针对文件的操作就是使用文件指针进行操作
2.文件指针 缓冲⽂件系统中关键的概念是“⽂件类型指针”简称“⽂件指针”每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区⽤来存放⽂件的相关信息如⽂件的名字⽂件状态及⽂件当前的位置等 这些信息是保存在⼀个结构体变量中的该结构体类型是由系统声明的这个结构体就叫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结构的变量并填充其中的信 息使⽤者不必关⼼细节 C语言⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量这样使⽤起来更加⽅便下面我们可以创建一个文件指针变量
FILE* pf;//⽂件指针变量这里定义的pf是⼀个指向FILE类型数据的指针变量可以使pf指向某个⽂件的⽂件信息区⼀个结构体通过该⽂件信息区中的信息就能够访问该⽂件。也就是说通过⽂件指针变量能够间接找到与它关联的⽂件如图
3.文件的打开和关闭 ⽂件在读写之前应该先打开⽂件在使⽤结束之后应该关闭⽂件现在我们就来学习如何打开和关闭文件 ANSI C 规定使⽤ fopen 函数来打开⽂件 fclose 来关闭⽂件在打开⽂件的同时它们都会返回⼀个FILE*的指针变量指向该⽂件也相当于建⽴了指针和⽂件的关系
文件的打开 我们来看看打开文件的函数fclose的原型
FILE * fopen ( const char * filename, const char * mode );如果文件打开成功了那么就会返回一个FILE*的指针我们可以用一个文件指针变量接收然后我们后续就可以通过这个文件指针变量对这个文件进行操作 如果文件打开失败了那么就会返回一个空指针NULL所以我们在使用fopen后最好再判断一下它的返回值是否是空指针如果是空指针说明文件打开失败直接返回 它的参数有两个第一个是我们要打开的文件的名字第二个参数是我们打开文件的方式是以读的方式还是写的方式还是读写等等方式如下图 在上图中展示了文件打开的方式以及如果文件不存在会做出什么操作现在我们还没有讲解怎么对文件进行读写所以有点懵也没有关系在后面的读写部分都会讲解这里只了解一下 接下来我们来试着写一个代码以只读的方式打开一个文本文件test.txt如下 FILE* pf fopen(test.txt, r);//打开文件//判断是否打开成功打开失败就返回错误信息并返回if (pf NULL){perror(fopen);return 1;}这样我们就打开了文件了至于读写操作我们后面讲现在先来看看如何关闭文件
文件的关闭 我们来看看关闭文件的函数fclose的原型
int fclose ( FILE * stream );它的返回值是int类型如果文件关闭成功就返回0如果文件关闭失败就返回EOF 它的参数是我们要关闭的流在这里我们要关闭文件就把文件的流也就是对应的文件指针变量传过来 我们要注意的是关闭文件后pf这个指针变量就指向野指针了所以最好关闭文件后将其置为空指针NULL我们来看看关闭文件关闭的过程
//关闭⽂件
int fclose (pf);
//为了防止pf成为野指针可以把它置为空指针
pf NULL;这就是我们关闭文件的过程接下来我们就学习最关键的文件读写操作
四、文件的顺序读写 文件的顺序读写就是按照文件数据从头到尾进行读写读写操作也是由我们的函数来完成的如下表 我们接下来就就一一讲解这些函数
1.fgetc函数 我们要学习的第一个函数是fgetc它的作用就是从流中获取一个字符不是应该属于输出吗那么为什么在表中它叫字符输入函数呢 这是我们要注意的一点我们说的输入输出是站在内存的角度思考的我们从流里面获取了一个字符对流来说也就是对文件来说是输出但是如果站在内存角度思考就会发现获取的字符存储到内存中了应该是属于输入所以我们说的输入输出都是基于内存角度的 实在不理解也没什么我们掌握它的用法就行我们来看看它的原型
int fgetc ( FILE * stream );它的参数就是我们要从哪个流里面获取一个字符在这里我们要操作文件很明显就是从文件流里面获取字符所以需要填一个文件指针变量进去 它的返回值是整型如果成功从文件中读取了一个字符那么就返回这个字符的Ascll码值如果读取失败或者读取到了文件末尾那么就返回EOF现在我们就来使用一下它 我们首先明确一下条件在当前代码路径下有一个test.txt的文件里面的内容是hello world!然后我们开始写代码由于这是第一遍所以我来带大家实现一下全过程后面文件的打开和关闭就不会再讲解了 首先我们要以读的形式打开文件然后用文件指针变量接收判断返回值是否为空如下
#include stdio.hint main()
{FILE* pf fopen(test.txt, r);if (pf NULL){perror(fopen);return 1;}return 0;
}随后我们就开始使用fgetc函数来实现读取操作用一个字符变量ch来接收它的返回值然后打印ch如下 char ch fgetc(pf);printf(%c\n, ch);随后就是最后一步关闭文件注意关闭文件后要把pf置为空指针如下
fclose(pf);
pf NULL;完整代码
#include stdio.hint main()
{FILE* pf fopen(test.txt, r);if (pf NULL){perror(fopen);return 1;}char ch fgetc(pf);printf(%c\n, ch);fclose(pf);pf NULL;return 0;
}最后我们来运行一下代码 可以看到我们成功读取了一个字符h那么问题来了如果我想将文件中的字符全部读出来怎么办呢我们也不是每一次都知道文件中有多少个字符 这个时候我们可以利用fgetc的返回值创建一个while循环只要fgetc的返回值不是EOF就一直循环每次循环把读取到的字符打印出来直到将所有字符读取完毕返回EOF结束循环如下 char ch 0;while ((ch fgetc(pf)) ! EOF){printf(%c, ch);}接着我们再次运行程序试试 可以看到这里就把文件中的所有字符都读出来了
2.fputc函数 fgetc函数和fputc函数很相似只是fgetc是将一个字符从流中读出而fputc的作用是将一个字符写入到文件中我们来看看它的原型
int fputc ( int character, FILE * stream );它的第一个参数就是我们要写入的字符第二个参数就是我们的流我们操作文件所以要写文件流 如果写入成功那么它的返回值就是这个字符的Ascll码值如果失败就返回EOF当然它的返回值我们很少用到 接着我们就使用一下这个函数这里要强调的一点是以写的方式打开文件第一步会清空文件中的内容然后再进行写的操作如果不想文件中的内容被清楚可以使用追加的方式打开 我们这里就可以使用写的方式打开test.txt文件让它将里面的hello world!删除了然后我们再使用fputc来写入一个字符如下
#include stdio.hint main()
{FILE* pf fopen(test.txt, w);if (pf NULL){perror(fopen);return 1;}char ch 0;fputc(x, pf);fclose(pf);pf NULL;return 0;
}运行代码后屏幕上没有出现任何信息接着我们就来看看test.txt文件有没有按预期被修改如图 可以看到hello world!已经被清除了并且字符x已经被我们写入到文件了
3.fgets函数 fgets函数的作用是从文件中读出一行的信息我们来看看它的原型
char * fgets ( char * str, int num, FILE * stream );它的第一个参数就是我们要把读出的一行数据放入哪个字符串第二个参数就是我们要读出几个字符最后一个参数就是要从哪个流中读取数据 如果读取成功那么它的返回值就是从文件中读取出的第一行的字符串的首地址可以使用%s的形式打印出来如果读取失败则会返回空指针NULL 接着就让我们使用一下这个函数首先明确前提当前目录下有一个test.txt的文件里面的内容有两行第一行是hello第二行是world!我们来读取它的第一行然后把它的第一行内容打印出来 char arr[20] { 0 };fgets(arr, 20, pf);printf(%s\n, arr);完整代码
#include stdio.hint main()
{FILE* pf fopen(test.txt, r);if (pf NULL){perror(fopen);return 1;}char arr[20] { 0 };fgets(arr, 20, pf);printf(%s\n, arr);fclose(pf);pf NULL;return 0;
}我们来看看代码运行截图 还是同样的问题如果我想将文件的所有行都读出来呢虽然我们现在知道有两行数据可以只调用两次fgets函数但是万一下次遇到很多行数据呢 所以这里我们还是要利用它的返回值创建一个while循环如果fgets没有返回空指针说明读取到了一行信息那么我们就把它打印出来如果返回空指针就结束循环如下 char arr[20] { 0 };while (fgets(arr, 20, pf)){printf(%s, arr);}我们来看看代码运行结果 可以看到代码自动把所有行打印出来了
4.fputs函数 fgets函数和fputc函数很相似只是fgets是将一行字符从流中读出而fputs的作用是将一行字符写入到文件中我们来看看它的原型
int fputs ( const char * str, FILE * stream );这个函数的第一个参数就是我们要写入的字符串第二个参数就是要写入的流 如果文件写入成功那么就返回一个非零的值如果写入失败就返回EOF 接着我们就来使用fputs向文件test.txt写入一行字符hello world!如下 char arr[20] hello world!;fputs(arr, pf);完整代码
#include stdio.hint main()
{FILE* pf fopen(test.txt, w);if (pf NULL){perror(fopen);return 1;}char arr[20] hello world!;fputs(arr, pf);fclose(pf);pf NULL;return 0;
}然后我们运行代码后来看看test.txt有没有被写入这一行信息 可以看到文件里已经成功写入了一行信息
5.fscanf函数 fscanf是以格式化的方式对文件进行读取操作它与scanf函数的使用方法相似它们的区别就是fscanf的第一个参数是流后面和scanf的参数一样我们来对比一下scanf和fscanf的原型
//scanf的原型
int scanf ( const char * format, ... );//fscanf的原型
int fscanf ( FILE * stream, const char * format, ... );可以看到它们的区别就是fscanf多一个流的选择它们的返回值也是一样的都是返回成功读取的项目的个数如果读取失败返回EOF如果还不熟悉scanf可以参考文章 【C语言】printf和scanf函数详解 我们这里也可以顺便说一下它们之间的关系scanf是从标准输入流读取数据而fscanf可以从任何流中读取数据那么fscanf也必然可以从标准输入流读取数据此时它们的作用就是一致我们在上面也说过标准输入流是stdin我们将fscanf的第一个参数写成标准输入流stdin就可以了如下
fscanf (stdin , const char * format, ... );
//等价于scanf说明了它们的关系我们就来示例使用一下fscanf我们的前提条件是当前文件夹下有一个test.txt文件里面包含的数据有123 hello现在我们要以格式话的方式将它们读取出来也就是将123读取为整型hello读取为字符串 首先我们要创建一个整型变量和一个字符数组用来存储我们读取到的信息然后将它们打印出来代码如下 int i 0;char arr[20] { 0 };fscanf(pf, %d %s, i, arr);printf(%d %s, i, arr);可以看到fscanf和scanf确实只有第一个参数的不同接着我们来看看完整的代码
#include stdio.hint main()
{FILE* pf fopen(test.txt, r);if (pf NULL){perror(fopen);return 1;}int i 0;char arr[20] { 0 };fscanf(pf, %d %s, i, arr);printf(%d %s, i, arr);fclose(pf);pf NULL;return 0;
}我们来看看代码运行结果
6.fprintf函数 fprintf函数和printf函数又非常相似也是第一个参数不同其它的使用方法一致fprintf的原型如下
int fprintf ( FILE * stream, const char * format, ... );它的返回值就不说了与printf一致不知道的可以看上面的链接有printf的详细使用教程它的参数也只是比printf多一个 它们只是作用不同fprintff的作用是向所有流中写入数据而printf是向标准输出流写入数据fprintf要全面一些当fprintf的第一个参数是标准输出流stdout的时候它的作用就和printf相同了如下
fprintf(stdout, const char * format, ... )
//等价于printf说完它们的关系我们就回到正题来使用一下fprintf函数对文件test.txt写入一些格式化的数据比如写入字符串world和浮点型的3.14如下
float f 3.14f;
char arr[20] world;
fprintf(pf, %s %f, arr, f);完整代码如下
#include stdio.hint main()
{FILE* pf fopen(test.txt, w);if (pf NULL){perror(fopen);return 1;}float f 3.14f;char arr[20] world;fprintf(pf, %s %f, arr, f);fclose(pf);pf NULL;return 0;
}接着我们运行代码来看看文件test.txt有没有被修改如下 可以看到文件被成功写入了格式化的数据
7.fwrite函数 我们要讲的最后两个函数fread和fwrite与上面讲的函数不同上面的函数都是对文件写入或读取我们看得懂的文本信息而这两个函数是对文件写入或读取二进制信息 也就是对二进制文件进行操作所以打开文件时要使用rb或者wb的方式我们首先来看看fwrite函数它是向文件写入二进制的信息它的原型如下
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );它的第一个参数是我们要写入的信息的首地址第二个参数size就是我们要写入的信息的一个元素的大小第三个参数count是我们要写入的元素的个数最后一个参数就是我们要往哪个流写入信息 它的返回值就是被成功写入文件的元素个数 接着我们就赶紧去使用一下fwrite为test.txt文件写入一些二进制信息我们要写的就是整型1到5我们可以使用数组的方式如下
int arr[] { 1,2,3,4,5 };
fwrite(arr, sizeof(arr[0]), 5, pf);然后我们来看看完整代码
#include stdio.hint main()
{FILE* pf fopen(test.txt, wb);//二进制写的方式打开if (pf NULL){perror(fopen);return 1;}int arr[] { 1,2,3,4,5 };fwrite(arr, sizeof(arr[0]), 5, pf);fclose(pf);pf NULL;return 0;
}然后我们来运行一下代码看看test.txt文件有没有发生改变 可以看到test.txt文件被写入了一些二进制信息但是我们看不出来是什么也就不知道里面是不是装的我们写入的整型1到5所以我们接下来学习对二进制文件信息进行读取的函数fread
8.fread函数 fread函数的作用就是从文件中读取二进制的信息刚好和fwrite搭配使用我们来看看它的原型
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );可以看到它的参数和返回值都和fwrite差不多没错它们的原型的含义基本一致这里就不多讲了 在刚刚使用了fwrite向文件写入了整型1到5后我们看不出来文件中的内容是否正确现在我们就使用fread将里面的信息读取出来看看是否是整型1到5如下 int arr[5] { 0 };fread(arr, sizeof(int), 5, pf);for (int i 0; i 5; i){printf(%d , arr[i]);}完整代码
#include stdio.hint main()
{FILE* pf fopen(test.txt, rb);if (pf NULL){perror(fopen);return 1;}int arr[5] { 0 };fread(arr, sizeof(int), 5, pf);for (int i 0; i 5; i){printf(%d , arr[i]);}fclose(pf);pf NULL;return 0;
}我们来运行代码看看fread帮我们从test.txt读出的信息是否是整型1到5 可以看到成功打印出来了整型1到5从这里也验证了之前我们的fwrite使用正确了 今天的分享就到这里结束啦虽然只是文件操作的一部分但是还是有一万字基本上讲完了我们在读写时使用的函数但是还是没有把文件操作部分要掌握的内容完全讲完 所以文件操作还有下一篇文章uu们敬请期待~ 那么今天说到这里bye~