文件操作【C语言】
1️⃣前言
在C语言的学习中,对于文件的操作是必不可少的,善于对文件进行操作可以帮助我们在运行程序时省去很多麻烦。例如我们可以把数据保存到文件中,当我们在运行程序时直接从文件中导入数据就避免了每次运行程序时都要先输入数据这一步骤。像是我们在做一些通讯录这样的小程序,都可以用到我们的文件这一操作,下面我们就来介绍一下C语言中对文件的一些操作。
对文件进行操作大致可以分为3大步骤:
1.打开文件
2.操作
3.关闭文件
下面我们就分这么3大步来对我们的文件进行分析。
2️⃣ 文件的打开和关闭
▶️文件指针
当我们想要对文件进行操作时,绕不开的是我们的文件指针。在缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名FILE
。我们一般都是通过一个FILE
的指针来维护这个FILE
结构的变量,这样使用起来更加方便。因此我们首先就需要来定义一个FILE*
的指针变量,如下代码:
FILE* pf;
定义pf是一个指向FILE
类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。
?️打开文件
文件在读写之前应该先打开文件。在编写程序的时候,在打开文件的同时,都会返回一个FILE*
的指针变量指向该文件,也相当于建立了指针和文件的关系。ANSIC 规定使用fopen
函数来打开文件。
fopen
函数传送门
FILE * fopen ( const char * filename, const char * mode );
文件的打开如果失败则返回一个NULL
指针,成功的话返回一个指向文件内容起始位置的指针。文件的打开方式有多种,如下表:
文件使用方式 | 含义 | 如果指定文件不存在 |
---|---|---|
“r”(只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
“w”(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
“a”(追加) | 向文本文件尾添加数据 | 建立一个新的文件 |
“rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb”(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
“ab”(追加) | 向一个二进制文件尾添加数据 | 出错 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+”(读写) | 为了读和写,建议一个新的文件 | 建立一个新的文件 |
“a+”(读写) | 打开一个文件,在文件尾进行读写 | 建立一个新的文件 |
“rb+”(读写) | 为了读和写打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,新建一个新的二进制文件 | 建立一个新的文件 |
“ab+”(读写) | 打开一个二进制文件,在文件尾进行读和写 | 建立一个新的文件 |
?关闭文件
ANSIC 规定使用fclose
函数来关闭文件。
fclose
函数传送门
int fclose ( FILE * stream );
文件的打开和关闭总是成对出现,当我们打开了一个文件并完成一系列的操作后,我们千万要记得关闭文件,打开和关闭文件代码示例如下:
#include <stdio.h>
int main()
{
FILE* pFile;
//打开文件
pFile = fopen("test.txt", "w");
//判断
if (pFile == NULL)
{
printf("打开失败!n");
exit(-1);
}
//文件操作
//略。。。
//关闭文件
fclose(pFile);
pFile = NULL;
return 0;
}
上述代码中,我们创建了一个pFile
的指针,并使用fopen
以w
只写的方式打开了一个名为test.txt
的文件,如果打开失败fopen
返回一个空指针给pFile
,因此我们在后面紧跟着就是对文件打开成功与否进行判断,打开成功的话我们就继续进行后面的文件操作,操作完成后接下来就是使用fclose
关闭文件,然后将pFile
置空。
3️⃣文件操作
对文件的操作我们有以下几种函数可以使用,如下表:
功能 | 函数名 | 适用于 |
---|---|---|
字符输入函数 | fgetc | 所有输入流 |
字符输出函数 | fputc | 所有输出流 |
文本行输入函数 | fgets | 所有输入流 |
文本行输出函数 | fputs | 所有输出流 |
格式化输入函数 | fscanf | 所有输入流 |
格式化输出函数 | fprintf | 所有输出流 |
二进制输入 | fread | 文件 |
二进制输出 | fwrite | 文件 |
我们可以看到这几种输入输出函数也是成双成对出现的,下面我们就一一对这四对函数进行分析。在分析这四组函数前,我们首先需要搞清楚输入输入的含义,当我们就字面看到的输入输出我们很有可能理解为输入就是从内存中输入到文件,输出就是从文件中输出到内存。如果我们是这样理解的话,那就恰恰相反了,我们所说的输入是从文件输入到内存,我们也可以把这个操作称为读操作。输出是从内存输出到文件,我们也可以把这个操作称为写操作。我们也可以用画图来更加清晰的表示,如下图。
⏪字符输入输出函数
fputc
为字符输出函数,可以进行写操作,将字符一个一个的写进文件里。
int fputc ( int character, FILE * stream );
我们通过以下代码来分析fputc
函数。
#include <stdio.h>
int main()
{
char arr[] = "abcdefg";
FILE* p = fopen("text.txt", "w");
if (p == NULL)
{
printf("打开失败!n");
exit(-1);
}
for (int i = 0; i < 26; i++)
{
fputc('a' + i, p);
}
fclose(p);
p = NULL;
return 0;
}
代码中,我们利用for
循环和fputc
函数将26个字母依次写入到名为text.txt
文件中,在程序运行完成后我们可以打开该文件观察,如下图所示:
在进行完写操作,我们还可以用fgetc
进行读操作。
fgetc
为字符输入函数,可以进行读操作,将字符一个一个的从文件读到内存中来,并且指针指向下一个数据。
int fgetc ( FILE * stream );
代码分析:
#include <stdio.h>
int main()
{
char arr[] = "abcdefg";
FILE* p = fopen("text.txt", "r");
if (p == NULL)
{
printf("打开失败!n");
exit(-1);
}
for (int i = 0; i < 26; i++)
{
printf("%c ", fgetc(p));
}
printf("n");
fclose(p);
p = NULL;
return 0;
}
代码中,我们利用for
循环和fgetc
函数将26个字母依次从text.txt
文件读出到内存中,然后我们用printf
打印出来,在程序运行后我们可以观察结果,如下图所示:
ℹ️文本行输入输出函数
fputs
是文本输出函数,可以进行文件写操作,可以将字符串写进文件中。
int fputs ( const char * str, FILE * stream );
fputs
函数的作用是将str
指针所指着的数据写入到stream
文件指针指着的文件中去。
代码分析:
#include <stdio.h>
int main()
{
FILE* p = fopen("text.txt", "w");
if (p == NULL)
{
printf("打开失败!n");
exit(-1);
}
fputs("hellon", p);
fputs("world", p);
fclose(p);
p = NULL;
return 0;
}
代码中,我们用fputs
函数分别将hello
和world
写进文件,其中hello
字符串中的n
也被写进了文件中,在文件中起到了换行的作用,我们运行完代码后可以打开文件观察内容,如下图:
fgets
为文本输入函数,可以进行读操作,将文件中的数据一行一行的读出来,读完一次后指针会自动指向下一行。
char * fgets ( char * str, int num, FILE * stream );
fgets
函数是将文件中的一行数据以最大num
个读出来后存放到str
数组中,如下代码:
#include <stdio.h>
int main()
{
char arr[] = "################";
FILE* p = fopen("text.txt", "r");
if (p == NULL)
{
printf("打开失败!n");
exit(-1);
}
fgets(arr, 5, p);
fclose(p);
p = NULL;
return 0;
}
代码中,我们定义了一个arr
数组,在上面我们就已经给text.txt
文件中写入了内容,所以这里我们就直接进行读操作就行了,我们用fgets
函数从文件中读出最多5个字符存放到arr
数组中。fgets
函数进行一次操作后会自动跳到下一行,其中当文件中一行的数据量大于最大读取数num
时,实际读取到的数据个数为num
-1个,最后一个会在后面补上一个,如下图:
当文件中一行的数据量小于读取数num
时,则实际读取到的个数为这一行的个数加上,如果有
n
的话,n
也会被读取,如下图:
?格式化输入输出函数
fprintf
为格式化输出函数,可以进行文件的写操作,将内存中的数据写入到文件中去
int fprintf ( FILE * stream, const char * format, ... );
fprintf
函数和printf
函数非常的相似,fprintf
的前面多了一个文件指针,表示把数据以某种格式写入到文件指针所指着的文件中去,具体如下代码演示:
#include <stdio.h>
int main()
{
FILE* p = fopen("text.txt", "w");
if (p == NULL)
{
printf("打开失败!n");
exit(-1);
}
int i = 5;
char arr[] = "abcdef";
fprintf(p, "%d %s", i, arr);
fclose(p);
p = NULL;
return 0;
}
代码中我们用fprintf
将整型i
和字符串arr
分别以%d
和%s
的格式写入到p
指针指着的文件中去,运行后我们可以打开文件查看,如下图:
与fprintf
相对应的fscanf
可以完成文件的读操作,可以把数据从文件中以格式化的形式读取到内存中来。
int fscanf ( FILE * stream, const char * format, ... );
fscanf
与scanf
函数相似,是以某种格式将数据从文件中读取出来,具体功能如下代码:
#include <stdio.h>
int main()
{
FILE* p = fopen("text.txt", "r");
if (p == NULL)
{
printf("打开失败!n");
exit(-1);
}
int x = 0;
char arr[] = "#########";
fscanf(p, "%d %s", &x, arr);
fclose(p);
p = NULL;
return 0;
}
代码中我们利用fscanf
函数将文件中的整型5
和字符串abcdef
分别以%d
和%s
的形式读出来并存放到x
变量和arr
数组中去,我们可以调试观察结果,如下图所示:
?二进制输入输出函数
与上面介绍的几个输入输出函数不同,上面介绍的几种输入输出函数适用于所有的输入输出流,而我们下面介绍的二进制输入输出函数适用于文件操作,并且是以二进制的形式进行读写。
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
fwrite
函数的作用是将ptr
指针所指的数据以size
个字节读取count
次并写入到stream
指针指向的文件中去,如下代码:
#include <stdio.h>
struct people
{
char name[20];
int age;
};
int main()
{
FILE* p = fopen("text.txt", "wb");
if (p == NULL)
{
printf("打开失败!n");
exit(-1);
}
struct people peop = { "wang", 15 };
fwrite(&peop, sizeof(peop), 1, p);
fclose(p);
p = NULL;
return 0;
}
代码中我们定义了一个结构体并且创建了一个结构体变量peop
后进行赋值,然后利用fwrite
函数将结构体写入到文件中,运行后观察文件中内容如下图:
因为fwrite
函数是以二进制形式进行写操作,所以在文件中可能会有我i们看不懂的字符。
与fwrite
函数相对应的二进制输入函数fread
,可以进行文件读操作。
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
fread
函数与fwrite
函数类似,将stream
指针指向的文件中的数据以size
个字节读取count
次然后放入到ptr
指针指向的内存中去,如下代码:
#include <stdio.h>
struct people
{
char name[20];
int age;
};
int main()
{
FILE* p = fopen("text.txt", "rb");
if (p == NULL)
{
printf("打开失败!n");
exit(-1);
}
struct people peop;
fread(&peop, sizeof(peop), 1, p);
fclose(p);
p = NULL;
return 0;
}
代码中我们创建了一个结构体变量peop
用于存放读取到的数据,然后利用fread
函数将文件中的数据以二进制的形式读取出来,我们调试观察结果,如下图所示:
4️⃣总结
文章中介绍了文件的基本操作,包括文件的打开关闭和文件的操作,文件的操作我们又介绍了几组文件的输入输出函数,大家看完如果觉得还不错的话就来个一键三连吧? !另外如果文章中出现错误或者纰漏还望指正,欢迎在评论区中评论。