欢迎光临
我们一直在努力

文件的操作函数学习

目录

1.文件名

2.二进制文件和文本文件

3.文件的打开与关闭

3.1流的概念

3.2文件指针

3.3文件的打开与关闭

4.文件的读写函数

4.1fputc与fgetc函数

4.2fputs与fgets函数

4.3fprintf和fscanf函数

4.4fwrite和fread函数

5.三组输入输出函数的对比

6.文件随机读写

7.总结上述函数返回值


我们平时在编程软件中编写的代码数据, 存储在电脑的内存中,如果程序结束,内存进行回收之后,这些数据就丢失了,当再次运行程序时,上一次程序的数据是看不到的,所以我们需要文件来对数据进行持久化的保存

从文件功能来说可以分为两类,程序文件和数据文件,程序文件包括源程序文件,目标文件,可执行程序,如下图,当我们创建一个文件进行程序编写时,就会生成如下几种文件

而数据文件是程序运行时读写的数据,例如从程序运行需要从某文件中读取数据,或者需要将数据写入某文件,这类文件叫做数据文件,这里主要介绍的就是数据文件

之前我们输入数据的时候,使用scanf函数从终端中输入数据,然后可以用printf函数打印到屏幕上

有时候我们会将信息输出到磁盘上的文件中,等需要的时候在读取到内存中使用,所以要学习文件的操作函数来达到目的

1.文件名

一个文件有一个唯一的文件标识,便于用户使用

文件标识包含三部分:文件路径+文件命名+后缀

为了方便,一般将文件标识叫做文件名

例如:D:\\C++2026\\code\\test2_9\\data.txt

2.二进制文件和文本文件

根据数据的组织形式,数据文件分为文本文件和二进制文件

一段用二进制存储的数据,如果不经过转换直接输出到文件中,那么就是二进制文件

而用ASCII码存储,需要在存储前进行转换,此时得到的以ASCII码形式储存的文件就是文本文件

使用代码写入数据12345,并以二进制文件形式打开观察结果,具体怎么操作下文会讲解

这里先根据结果,了解存储数据的方式

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {

int a = 12345;
FILE* pf = fopen("data.txt", "wb");
fwrite(&a, 4, 1, pf);//⼆进制的形式写到⽂件中
fclose(pf);
pf = NULL;
return 0;
}

因为当前环境是小端,所以12345的二进制形式先四位一转,转换成16进制是00 00 30 39

因为小端低字节放到低地址,所以结果是39 30 00 00

3.文件的打开与关闭

3.1流的概念

因为各种外部设备的输入输出的操作不同,为了方便对各种设备进行操作,抽象出一个流的概念

在外部设备和数据之间有一层流,当我们需要读取数据或者写入数据时,通过这个流进行操作

可以理解为一把万能钥匙,不管什么房间,只要使用这把万能钥匙,我们就可以打开门,进行“数据的存储或者数据的读入”

但是我们之前在使用scanf和printf函数输入数据和打印数据时,为什么没有打开流呢

其实在程序启动时,会默认打开三个流

1.stdin标准输入流,大多数环境中从键盘输入–scanf函数

2.stdout标准输出流,大多数环境是输出到屏幕上,打印数据–printf

3.stderr标准错误流,当出现错误时,输出到显示器界面,专门输出错误信息

因为默认打开了这三个流,所以我们可以直接使用scanf和printf函数进行输入与输出操作

3.2文件指针

流也具有一个类型:FILE*,称为文件指针,我们通过文件指针来维护流的操作

 每个被使用的文件都在内存中有一个相应的文件信息区,用来存放文件相关信息,这些信息保存在一个结构体变量中,取名FILE

当打开一个文件时,系统会根据文件情况自动创建一个FILE结构的变量

3.3文件的打开与关闭

在对文件进行操作前,我们要先打开文件,使用结束后,应关闭文件,并将指针置为空

打开文件使用fopen函数,关闭函数使用fclose函数

fopen函数有两个参数,第一个是需要打开的文件,可以用绝对路径也可以是相对路径,第二个是以什么方式打开

返回值是一个FILE类型的指针,如果打开文件失败则返回NULL

fclose使用时,放入要关闭的文件的文件指针,即可关闭相应文件,返回值是一个整型,如果关闭成功返回0,关闭失败返回EOF

这是一个简单的例子,我们以只写方式打开了同目录下的data.txt文件,然后操作完进行关闭吗,并将指针置为NULL避免野指针

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {

FILE* pf = fopen("data.txt", "w");
if (pf == NULL) {
perror("fopen");
return 1;
}
//在文件内写入数据
fclose(pf);//关闭文件
pf = NULL;//避免野指针

return 0;
}

下面提供一个表格—-文件的常用打开方式,可以根据需要使用

4.文件的读写函数

文件读写需要使用很多种函数,下面进行逐个讲解

4.1fputc与fgetc函数

fputc用于向文件中写入字符,第一个参数是目标字符,第二个参数是输出流,可以传入一个文件指针,可以传入stdout标准输出流(把数据放到屏幕上而不是文件内)

功能是将指定字符放到光标指示器所在的位置,并且自动将光标移动一个位置

如果放入成功则返回写入字符的int形式,放入失败则返回EOF,会设置一个错误指示器,可以通过ferror函数检查错误(后续会讲)

通过代码理解该函数,每次放入一个小写字母,最终在文件中放入了26个小写字母,在文件中查看结果即可看出

#include<stdio.h>
int main() {

FILE* pf = fopen("data.txt", "w");
if (pf == NULL) {
perror("fopen");
return 1;
}
for (int i = 'a'; i < 'z'; i++) {
fputc(i, pf);
}
fclose(pf);
pf = NULL;

return 0;
}

fgetc函数用于读取文件中已经存在的数据或者标准输入流的数据(直接从键盘输入)

例如我们刚才在data.txt文件中放入了26个小写字母,用fgetc函数读取,每次会读取一个字符,然后光标指示器前进到下一个字符之前,如果成功读取则返回读取字符的int形式,读取失败则返回EOF,并设置错误指示器ferror,如果已经读取到末尾了,则设置文件结束指示器feof

这里插入讲解一下feof与ferror,当文件读取到末尾,读取函数会设置一个文件结束的指示符,可以用feof函数检测,如果检测到该指示符,则feof函数返回非0,没检测到返回0

ferror函数也是类似,如果发生读取错误,则设置一个错误指示符,使用ferror函数检测,如果检测到则返回非0,如果没检测到0

两者参数都是流的指针

下面根据代码理解一下函数的使用

注意每次调用fgetc时都会读取一个字符并移动光标,所以要用一个变量接收后,用变量去进行判断,不然可能会出现跳过几个字符打印的问题

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {

FILE* pf = fopen("data.txt", "r");
if (pf == NULL) {
perror("fopen");
return 1;
}
for (int i = 0; i < 30; i++) {
int c = fgetc(pf);
if (c == EOF) {
if (feof(pf)) {
printf("文件已经读取到末尾了\\n");
break;
}
else if (ferror(pf)) {
printf("文件读取错误\\n");
break;
}
}
fputc(c, stdout);
//在屏幕上打印读取到的字符
//stdout是标准输出流
}
fclose(pf);
pf = NULL;

return 0;
}

4.2fputs与fgets函数

用法与fputc和fgetc类似,只不过将字符换成了字符串,用来写入字符串和读取字符串

str是需要写入的字符串(必须以\\0结尾)的指针,stream指向要写入字符串的流

写入成功,返回非0值,写入失败返回EOF,并设置错误指示器

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {

FILE* pf = fopen("data.txt", "w");
if (pf == NULL) {
perror("fopen");
return 1;
}
fputs("abc\\n", pf);
fputs("123", pf);
fclose(pf);
pf = NULL;

return 0;
}

str指向用来存储读到的字符串的空间,num是最大读取的字符个数,实际上最多读取num-1个,因为要留出一个给\\0,读取num-1个字符后会自动在末尾加上\\0

如果读取到换行符,EOF(文件末尾),或者达到指定字符个数,此时将读取到的字符串存储到目标空间str中,stream是输入流的指针,可以是文件流也可以是stdin(标准输入流,从键盘输入)

如果读取成功,返回str指向空间的首地址,读取失败则返回NULL,并设置错误指示器

如果在读取过程中,读到了文件末尾,则设置文件结束指示器,读取错误则设置错误指示器

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {

FILE* pf = fopen("data.txt", "r");
if (pf == NULL) {
perror("fopen");
return 1;
}
char test1[] = "xxxxxxxxxxxxx";
fgets(test1, 6, pf);
//因为abc\\n不足6字符,且末尾有\\n,读取到\\n即停止,并在末尾加上一个\\0
printf("%s",test1);
char test2[] = "xxxxxxxxxxxxx";
fgets(test2, 6, pf);
//123也不足6个字符,读取三个即可,自动加上一个末尾的\\0
printf("%s", test2);

fclose(pf);
pf = NULL;

return 0;
}

4.3fprintf和fscanf函数

对于fprintf函数,它是针对所有流的输出函数,可以是标准输出流,也可以是文件流

用法直接类比printf函数即可,只不过多了一个参数,用于接收流的类型

如果输出成功,返回输出的项数,输出失败,先设置错误指示器,并返回负值

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct stu {
int age;
char name[20];
float score;
};
int main() {
struct stu s1 = { 20,"zhangsan",89.1 };
FILE* pf = fopen("data.txt", "w");
if (pf == NULL) {
perror("fopen");
return 1;
}
//printf("%d %s %f",s1.age,s1.name,s1.score);
fprintf(pf, "%d %s %f", s1.age, s1.name, s1.score);
//只要会用printf函数,fprintf只是多了一个流参数而已

fclose(pf);
pf = NULL;

return 0;
}

fscanf函数和scanf函数也是类似,只是多了一个流参数

fscanf函数是针对所有流的输入函数,可以用来解析文件中的格式化数据

如果读取成功,返回填充到列表中的项数,如果返回小于预期的项数,可能是格式不匹配,读取到文件末尾或者读取错误,如果读取错误设置错误指示器,读取到末尾则设置文件末尾指示器

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct stu {
int age;
char name[20];
float score;
};
int main() {
struct stu s1 = {0};
FILE* pf = fopen("data.txt", "r");
if (pf == NULL) {
perror("fopen");
return 1;
}
//scanf("%d %s %f",&(s1.age),s1.name,&(s1.score));
int r= fscanf(pf,"%d %s %f",&(s1.age),s1.name,&(s1.score));
printf("读取了%d项\\n", r);
printf("%d %s %f\\n", s1.age, s1.name, s1.score);

fclose(pf);
pf = NULL;

return 0;
}

4.4fwrite和fread函数

这是一组用于二进制数据的输入与读取

要保证目标文件以二进制可读或可写方式打开,才能正常操作

第一个参数ptr是要写入数据块的指针,第二个参数size是每个数据的大小

第三个参数count是总共有多少个数据,第四个参数stream是目标文件指针

返回值时写入的数据项

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
FILE* pf = fopen("data.txt", "wb");
if (pf == NULL) {
perror("fopen");
return 1;
}
int data[] = { 1,2,3,4,5 };
fwrite(data, sizeof(int), 5, pf);

fclose(pf);
pf = NULL;

return 0;
}

fread函数用于从文件中读取二进制数据,并存储到一个空间中

ptr是存储空间,且必须足够大以存储数据,size是每个数据的大小,count是读取数据的个数,stream是目标文件指针

返回值是实际读取的数据个数

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
FILE* pf = fopen("data.txt", "rb");
if (pf == NULL) {
perror("fopen");
return 1;
}
int data[10] = {0};
int r= fread(data, sizeof(int), 5, pf);
for (int i = 0; i < 5; i++) {
printf("%d\\n", data[i]);
}
printf("读取了%d个数据\\n", r);
fclose(pf);
pf = NULL;

return 0;
}

5.三组输入输出函数的对比

sprintf和sscanf函数写法也是和之前的输入输出函数类似,只不过第一个参数换成了目标字符串的地址,用于将格式化数据填入字符串或者从字符串中提取格式化数据

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct stu {
int age;
char name[20];
};
int main() {
struct stu s = { 20,"zhangsan" };
char arr[40] = { 0 };
sprintf(arr, "%d %s", s.age, s.name);
//成功则返回输入的字符数,失败返回负值,注意占位符之间的空格也会算作字符被记入
//应返回11
printf(arr);
//字符串中无数据,用sprintf向字符串中输入格式化数据
struct stu s1 = { 0 };
char arr1[] = { "21 lisi" };
sscanf(arr1, "%d %s", &(s1.age),s1.name);
//成功返回获取的参数数量,失败则返回负值,这里的空格不会计入参数数量
//应返回2
//字符串中有数据,用sscanf函数将数据格式化存储到结构体中

return 0;
}

6.文件随机读写

在文件读写时不一定要按照一个一个顺序,我们可以使用一些函数调整光标的位置

fseek函数可以根据第三个参数提供的位置,以及第二个参数说明移动的个数,改变当前光标所在的位置

最好是在二进制文件中使用,在文本文件中使用结果可能不确定

origin只有三种取值

SEEK_SET :文件开始位置 SEEK_CUR :文件指针当前的位置 SEEK_END :文件末尾位置

offset可以是正数也可以是负数,表示向文件末尾移动或者向文件开头移动

移动成功则返回0,移动失败返回负值

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
FILE* pf = fopen("data.txt", "rb");
fseek(pf, 4, SEEK_SET);
int c=fgetc(pf);
printf("%d", c);

return 0;
}

因为一开始指向01,因为原来的二进制文件中存入了12345五个整型,所以跨过四个字节可以获取到02的数据,输出结果应该是2

ftell函数用于获取当前光标位置离文件开头的字节数,返回值即为离文件开头字节数

主要也是运用在二进制文本中

rewind函数相当于重置读写状态,会清除错误指示器或者文件末尾指示器

而使用fseek函数从头开始读写不会重置错误指示器和文件末尾指示器

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
FILE* pf = fopen("data.txt", "rb");
fseek(pf, 4, SEEK_SET);
int c=fgetc(pf);
printf("当前获取了%d\\n", c);
int c1 = ftell(pf);
printf("当前离文件开头%d字节\\n", c1);
rewind(pf);
int c2 = fgetc(pf);
printf("当前获取了%d\\n", c2);

return 0;

7.总结上述函数返回值

fopen:打开成功返回一个文件指针,失败返回NULL

fclose:关闭成功返回0,关闭失败返回EOF

如果读到末尾则设置文件末尾指示器,读写错误设置错误指示器

fputc:成功返回放入字符的int值,失败返回EOF

fgetc:成功返回获取到字符的int值,失败返回EOF

fputs:成功放入返回非0,失败返回EOF

fgets:成功返回目标空间首地址,读取失败返回EOF

fprintf:成功返回输出的项数,失败返回负值

fscanf:成功返回存入的项数,失败返回EOF

fwrite:成功返回写入数据项数,发生错误返回值可能小于写入项数

fread:成功返回读取项数,发生错误返回值可能小于读取项数

sprintf:成功返回写入的字符数,失败返回负值

sscanf:成功返回获取的参数数量,失败返回负值

fseek:移动成功返回0,失败返回负值

ftell:成功返回当前位置距离文件开头的字节数,失败返回-1

rewind:无返回值

赞(0)
未经允许不得转载:171主机测评 » 文件的操作函数学习
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址