作者:喜欢猫咪的的程序员
专栏:《C语言》
喜欢的话:世间因为少年的挺身而出,而更加瑰丽。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ——《人民日报》

目录
什么是文件:
我们为什么要使用文件呢?
文件分类:
我们将文件分为以下两种:
程序文件:
?编辑数据文件?:
文件名:?
文件的打开和关闭:
文件指针:
什么是文件指针:
如何定义一个文件指针:
文件信息区前提引入:?
文件的打开和关闭:
fopen函数:
相对入径和绝对入径:
关闭文件:
fclose函数:
?输入流和输出流:
?文件的输入流和输出流可能会出现的问题:
文件的顺序读写:
文件操作函数有哪些呢?如下:
文件的输入和输出流函数(顺序读写):
fgetc函数和fputc函数:
?fgets和fputs函数:
fread函数和fwrite函数:
?我们来对比几个函数:
文件的随机读写:
fseek函数:
ftell函数:?
?rewind函数:
文本文件和二进制文件:
文件读取结束的判定:
feof函数:
文件缓冲区:?
什么是文件:
文件属于文件的一种,与普通文件载体不同,文件是以硬盘为载体存储在计算机上的信息集合。
我们为什么要使用文件呢?
- 但我们在运行代码时,我们每次都得初始化或者输入数据,这些数据在程序运行完成后也会消失。
- 在程序运行开始之前或者运行结束之后,数据都没有了,文件这个时候就可以起到至关重要的作用了,它可以为我们存储数据。
文件分类:
我们将文件分为以下两种:
文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。
程序文件:
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。
如同下图第一个文件:
数据文件?:
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。
本章讨论的都是数据文件。
文件名:?
文件名是文件的标识符。
文件名包含3部分:文件路径+文件名主干+文件后缀?

文件的打开和关闭:
文件指针:
什么是文件指针:
在C语言中用一个指针变量指向一个文件,这个指针称为文件指针。通过文件指针就可对它所指的文件进行各种操作。
如何定义一个文件指针:

定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。?
文件信息区前提引入:?
我们文件操作分为3个部分:

?当我们在读或者写文件的时候,都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。

我们可以创建一个文件指针: FILE* pf。
定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。这样就可以找到与它相关的文件信息区了。
文件的打开和关闭:
- 文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
- ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。?
fopen函数:

?第一个参数为文件名,第二个为打开方式。
打开方式有特定的写法,不同的字母有不同的含义,如下图?

- ?当打开方式为r或者r+时,打开前文件必须存在,其他几个如果打开前文件不存在,就会创建一个文件。
详细如下:

- 返回值:如果返回成功,就返回一个FILE*指针,如果第一个参数(filename)为空的话,就返回一个NULL空指针。
- 因此就会有存在空指针的风险,所以我们就要在打开文件后,判断是否为空指针。
如何预防空指针如下:

相对入径和绝对入径:

- ?注意:绝对入径原本为"D:\code:\code.txt",但计算机的认知中\会与c结合成\c,成为一个转义字符。所以我们要用一个\来转义例外一个\,因此变为"D:\\code\\code.txt"
关闭文件:
fclose函数:

- ?参数:为文件指针的起始地址。
- 因为我们一般会将文件指针的地址赋给一个指针,fclose函数只是关闭文件,而并没有将这个指针置为空指针。
?文件的开启和关闭实际运用:

?输入流和输出流:
我们先来看一下我们正常的输入流和输出流。

?我们这边的内存,我们可以理解为计算机或者编译器。
然后我们来看一下文件的输入流和输出流流:

?我们这可以将内存当做计算机,举个例子:使用fgets函数,文件就相当于一般情况下的键盘,我们是将文件中原本存好的数据读取给了计算机(内存),所以fopen要写为r。
?文件的输入流和输出流可能会出现的问题:
在了解输入流和输出流函数前,我们首先得了解一个地方,不然程序会出现问题。都是博主经历过的血与泪!!!
- 当我们要输入时:我们应该要将打开文件fopen函数中的打开方式改为“r”或者其他与写有关的。
- 当我们要输出时:我们应该要将打开文件fopen函数中的打开方式改为“w”或者其他与读有关的。

了解完这个后,我们来了解一下输入流和输出流函数!
文件的顺序读写:
文件操作函数有哪些呢?如下:

我们来了解一下这些函数。
文件的输入和输出流函数(顺序读写):
- 以下函数的头文件都为#include<stdio.h>
fgetc函数和fputc函数:

?实际运用:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{//打开文件
//相对入径
FILE* pf=fopen("test.txt", "r");
//绝对入径
//FILE* pf=fopen("D:\\code\\code.txt", "w");
if (pf == NULL)
{//fopen函数的返回值是file*的,可能会传回来空指针,所以要判断一下。
perror("fopen");
return 1;
}
// 写文件
fputc('a', pf);
fputc('b', pf);
fputc('c', pf);
int i = 0;
/*for (int i = 0; i < 26; i++)
{
fputc('a' + i, pf);
}*/
//int ch = fgetc(pf);
//printf("%c ", ch);
/*for (int i = 0; i < 26; i++)
{
int ch = fgetc(pf);
printf("%c ", ch);
}*/
//结束文件
fclose(pf);//这个不会将pf设为空指针,我们要将pf设为空指针
pf = NULL;
return 0;
}
?运行结果:
?fgets和fputs函数:

?如何运用:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
//打开文件
char*pf=fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen:");
return 1;
}
//写文件
char ch[20]="qqqq";
fgets(ch, 20, pf);
printf("%s\n", ch);
//关闭文件
fclose("test.txt");
pf = NULL;
return 0;
}
?运行结果:

?fputs函数我就不讲如何使用了,就是记得把fopen函数的r改为w。
fread函数和fwrite函数:
fread函数:

参数:
- ptr为指向大小至少为(size*count)字节的内存块的指针,转换为 void*。
- size为每个元素的大小。
- count为个数
- stream为文件指针。
用处:
- 从输入流中读取数据到内存到内存
- 流的位置指示器按读取的字节总数前进。
- 如果成功,读取的总字节数为(大小*计数)。
返回值
- 返回值为size_t类型。返回成功读取的元素总数。
- 如果此数字与 count 参数不同,则表示读取时发生读取错误或到达文件末尾。
- 如果大小或计数为零,则该函数返回零,并且 ptr 所指向的流状态和内容保持不变。
?fwrite函数:

参数:?
- ptr为指向指向要写入到文件的元素数组的指针。
- size为要写入的数组每个元素的内存大小。
- count为个数
- stream为文件指针
用处:
- 将元素数组从计算机(内存)写到文件。
- 流的位置指示器按写入的总字节数前进。
- 在内部,该函数将 ptr 所指向的指针解释为一个无符号 char 类型的(大小*计数)元素数组,并按顺序将它们写入输出流,就好像为每个字节调用了 fputc 一样。
返回值:
- 为size_t类型
-
如果成功,就返回写入元素的个数 -
如果返回值与count的值不一样,就会报错 -
如果大小或计数为零,则该函数返回零,
?实际运用:

这里要注意:
- 如果是要写二进制文件,fopen的打开方式不能写r或者w,要写wb或者rb。
- fread和fwrite函数不仅能用在文本文件还可以运用在二进制文件,而其他几个只能运用在文本文件。
?我们来对比几个函数:
scanf/fscanf/sscanf? ? ? ?
printf/fprintf/sprintf
??显而易见,上图蓝色部分是相同的,而红色部分不一样。

?我们对比一下,发现printf函数和scanf函数加个f。多的那个变量为文件指针。例如:fprintf函数就是将变量从内存按照一定的格式输出到数据(文件)中。fscanf也是同样的道理。
而我们可以将变量以一定格式转换输入输出到数据,那我们是否可以将这些格式化的数据变回原来的格式呢?
答案是可以的,就是运用上图下面两个函数(sprintf函数和sscanf函数)。
如何运用呢?如下:

我们在一些网站或者平台(前端)注册的时候,要填写一些数据,这些数据就是字符串,我们就可以运用sscanf函数和sprintf函数来运用。?
文件的随机读写:
fseek函数:

?参数:
-
第一个参数为文件指针 -
第二个为偏移量 -
第三个为偏移量的起始位置 SEEK_SET为文件起始位置 SEEK_CUR为文件某个指定位置 SEEK_END为文件结尾位置?
?实际运用:

ftell函数:?
ftell函数是返回文件指针相对于起始位置的偏移量。

参数:stream为文件指针。
返回值为:为long int型?
实际运用:

?rewind函数:
让文件指针的位置回到文件的起始位置

实际运用:?
/* rewind example */
#include <stdio.h>
int main ()
{
?int n;
?FILE * pFile;
?char buffer [27];
?pFile = fopen ("myfile.txt","w+");
?for ( n='A' ; n<='Z' ; n++)
??fputc ( n, pFile);
?rewind (pFile);
?fread (buffer,1,26,pFile);
?fclose (pFile);
?buffer[26]='\0';
?puts (buffer);
return 0;
}
文本文件和二进制文件:
根据数据的组织形式,数据文件被称为文本文件或者二进制文件。
一个数据在内存中是怎么存储的呢?
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。

文件读取结束的判定:
feof函数:

- 应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束?
- 而不是文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束
文件缓冲区:?
ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。

因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。
|