文件的概念

文件标识

C12_1

1、每个文件要有一个唯一的文件标识,以便于用户识别和引用

2、文件标识包含3部分:文件路径+文件名+文件后缀。

3、同一系统下不存在两个完全相同的文件标识

文件分类

根据其数据存储方式和内容的特点:

文本文件:

是一种计算机文件,其中存储的是纯文本数据,通常使用ASCII码或Unicode编码进行表示。它包含的内容通常是人类可读的文本,比如字母、数字、标点符号和其他可打印字符,而不包含二进制数据或特殊格式。

格式:txt、csv、xml、html

二进制文件:

是一种计算机文件,其中存储的是以二进制形式表示的数据二进制文件可以包含各种类型的数据,如图片、音频、视频、可执行代码等。它们通常由特定的程序或应用程序进行创建和处理。

格式:JPEG、MP3、MP4、EXE

文本文件 二进制文件
存储方式 文本形式存储的文件,使用字符编码(如ASCII或Unicode)来表示字符 字节(8位)的形式
内容表示 内容是以可读的文本形式呈现,可以直接打开并查看。 通常是非文本数据,如图像、音频、视频等,不可直接阅读。
可编辑性 可以使用文本编辑器直接编辑和修改 需要使用专门的程序或工具进行编辑和修改
文件大小 使用了较多的字符编码来表示文本内容,故较大 直接以字节形式存储,节省了存储空间
跨平台兼容性 较好的兼容性 在不同操作系统之间可能存在兼容性问题

总结: 文本文件适合存储和传输可读的文本数据,而二进制文件适合存储和处理非文本的二进制数据。具体选择使用哪种文件类型取决于你的需求和所处理的数据类型。

文件作用

文件是计算机中存储和管理数据的一种方式,它具有存储、传输、持久性和访问控制等功能。

FILE类型介绍

IO流的概念

我们把这种数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,按照数据流向分为输入input 和输出output ,即流向内存是输入流,流出内存的输出流。

FILE介绍

C语言中I/O操作主要是指使用FILE结构体下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写入数据。

在C语言中,FILE是一个结构体类型,用于表示文件流。它是通过标准库中的文件操作函数来进行文件读写的重要数据类型。

1
2
3
4
5
6
#include <stdio.h>//文件操作需要用到stdio.h头文件中提供的函数和结构体
int main()
{
FILE* file_ptr = NULL; //声明一个 FILE 类型的指针
return 0;
}

标准库函数

IO的分类

根据数据的流向分为:输入流 、输出流

根据数据的类型分为:字符输入输出流、文本输入输出流、格式化输入输出流、数据块输入输出流

功能 函数原型
打开文件 fopen(const char* filename, const char* mode)
关闭文件 fclose(FILE* filename)
字符读取函数 fgetc(FILE *stream)
字符写入函数 fputc(int char, FILE *stream)
文本行读取函数 fgets(char *str, int n, FILE *stream)
文本行写入函数 fputs(const char *str, FILE *stream)
格式化读取函数 fscanf(FILE *stream, const char *format, …)
格式化写入函数 fprintf(FILE *stream, const char *format, …)
数据块读取 fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
数据块写入 fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)

文件的操作

实现操作 函数 说明
打开文件 fopen函数 打开一个文件
读取文件 fread、fgetc、fgets、fscanf函数 文件中读取数据
写入文件 fwrite、fputc、fputs、fprintf函数 将数据写入文件
关闭文件 fclose函数 关闭文件,释放资源

文件的打开与关闭

打开文件:FILE* fopen(const char* filename, const char* mode);

说明:1、const char* filename:需要打开的文件标识。
2、const char* mode:这个参数指定了打开文件的方式。

关闭文件:int fclose(FILE* filename);

说明:FILE* filename:这个参数是需要关闭的文件的文件指针。

文件使用方式 含义 如果指定文件不存在
“r”(只读) 为了输入数据,打开一个已经存在的文本文件 出错
“w”(只写) 为了输出数据,打开一个文本文件 建立一个新的文件
“a”(*追加) 向文本文件尾添加数据 建立一个新的文件
“rb”(只读) 为了输入数据,打开一个二进制文件 出错
“wb”(只写) 为了输出数据,打开一个二进制文件 建立一个新的文件
“ab”(追加) 向一个二进制文件尾添加数据 出错
“r+”(读写) 为了读和写,打开一个文本文件 出错
“w+”(读写) 为了读和写,建议一个新的文件 建立一个新的文件
“a+”(读写) 打开一个文件,在文件尾进行读写 建立一个新的文件
“rb+”(读写) 为了读和写打开一个二进制文件 出错
“wb+”(读写) 为了读和写,新建一个新的二进制文件 建立一个新的文件
“ab+”(读写) 打开一个二进制文件,在文件尾进行读和写 建立一个新的文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>
int main()
{
FILE *fp = NULL;
char filename[] = "1.txt";
fp = fopen(filename,"r");//打开文件(打开文件的名称,以只读读的方式打开)
//以上三行可简化:FILE* fp = fopen("1.txt","r");
//检查文件是否成功打开
if(fp == NULL)
{
printf("无法打开文件%s\n",filename);
}
else
{
printf("打开文件%s\n",filename);
}
//关闭文件操作
fclose(fp);
return 0;
}

注意事项:
1、总是检查fopen的返回值:确保文件已成功打开。
2、使用fclose关闭文件:避免资源泄漏并确保写入操作被保存。

字符读取、写入

字符写入:int fputc(int c, FILE *stream);

说明:1、int c:需要写入的字符;
2、FILE *stream:指向要写入的文件的文件指针;
3、返回值:成功时返回写入的字符的ASCII码值,失败时返回EOF(-1)。

字符读取:int fgetc(FILE *stream);

说明: 1、FILE *stream:指向FILE类型的指针,表示要读取字符的文件流;
2、返回值:读取的字符,以整数形式返回。如果读取成功,返回读取的字符的ASCII码值;如果到达 文件 末尾或者出现错误,返回EOF(-1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<stdio.h>
int file_copy()
{
char ch = '\0';
//打开源文件
FILE *sourceFile = fopen("source.txt", "r");//读指针

//创建目标文件
FILE *destinationFile = fopen("destination.txt", "w");//写指针
if(NULL == sourceFile){
perror("打开源文件失败的原因\n");
return 1;
}
if(NULL == destinationFile){
perror("创建目标文件失败的原因\n");
return 2;
}
while(-1 != (ch = fgetc(sourceFile)))
{
fputc(ch, destinationFile);
}
printf("文件复制成功。\n");
fclose(sourceFile);
fclose(destinationFile);
return 0;
}
int main()
{
int flag = file_copy();
if(0 == flag)
{
printf("文件拷贝成功\n");
}
if(1 == flag)
{
printf("打开源文件失败\n");
}
if(2 == flag)
{
printf("打开目标文件失败\n");
}
return 0;
}

文本行读取、写入

**文本行写入:**int fputs(const char *str, FILE *stream);

说明:1、const char *str:要写入文件的字符串,以空字符(‘\0’)结尾;
2、FILE *stream:指向要写入的文件的文件指针;
3、返回值:成功写入时,返回非负值,写入失败时,返回EOF(-1)。
4、fputs每次写入一行文本数据到文件,fputs不会自动添加换行

**文本行读取:**char *fgets(char *str, int n, FILE *stream);

说明:1、char *str:指向一个字符数组的指针,用于存储读取的字符串;
2、int n:最大读取字符数,包括换行符和终止符;
3、FILE *stream:指向一个文件流的指针;
4、返回值:是一个指向存储的字符串的指针,如果读取失败或到达文件结束,返回NULL。
注意:fgets每次读取指定数量的字符,实际读入的字符个数等于指定的数量-1,并主动在最后添加’\0’。
fgets每次只能读取一行字符,如果需要连续读取多行字符,可以使用循环结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
int main()
{
FILE *pfile = fopen("source.txt","r");
if (pfile == NULL)
{
perror("文件打开失败");
return 1;
}
char buffer[100] = {};
fgets(buffer,10,pfile);
printf("%s\n",buffer);
fclose(pfile);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
FILE *pfile = fopen("destination.txt","w");
if (pfile == NULL)
{
perror("文件打开失败");
return 1;
}
fputs("hello world\n",pfile);
fclose(pfile);
return 0;
}

格式化读取、写入

**格式化写入:**int fprintf(FILE *stream, const char *format, …)

说明:1、FILE *stream:指向一个文件流的指针;
2、const char *format:格式字符串,用于指定数据的读取格式;
3、后面的参数根据格式字符串中的格式符来决定,和printf类似;

注意:
printf可以把非文本数据(格式化数据)转为文本数据,然后在写入文件,fprintf并不能写入非文本数据。

**格式化读取:**int fscanf(FILE *stream, const char *format, …)

说明:1、FILE *stream:指向一个文件流的指针;
2、const char *format:格式字符串,用于指定数据的读取格式;
3、后面的参数根据格式字符串中的格式符来决定,和scanf类似;
4、返回值:是成功匹配并读取的数据项数,有三种结果。如果成功读取并匹配了指定的数据项,则返回成 功读取的数据项数。如果发生了读取错误或遇到文件结束,返回EOF(-1)。

注意:如果fscanf函数在读取过程中遇到无法匹配的数据项或者读取错误,会停止读取后续数据项,直接返回当前已成功读取的数据项数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
int main()
{
FILE *fp = fopen("text1.txt","w");
if (fp == NULL)
{
perror("文件打开失败");
return 1;
}
int num;
scanf("%d",&num);
fprintf(fp,"%d",num);
fclose(fp);
fp = fopen("text1.txt","r");
if (fp == NULL)
{
perror("文件打开失败");
return 1;
}
fscanf(fp,"%d",&num);
printf("文件中读取的数据:%d\n",num);
fclose(fp);
return 0;
}

数据块的读取、写入

**数据块写入:fwrite(const void ptr, size_t size, size_t nmemb, FILE stream)

说明:1、const void* ptr:指向你想写入文件的数据;
2、size_t size:每个数据元素的大小,以字节为单位。
例如:写入一个整数数组,则该值应该是sizeof(int);
3、size_t nmemb:要写入的数据元素的个数;
4、FILE* stream:指向要写入的文件的指针。
5、返回值:实际写入的数据块数量。

**数据块读取:int num=fread(void ptr, size_t size, size_t nmemb, FILE stream)

说明:1、void* ptr:指向存储数据的缓冲区的指针,即每次读取的内容放在缓冲区内;
2、size_t size:每个数据元素的大小,以字节为单位。
例如:读取一个整数数组,则该值应该是sizeof(int);
3、size_t nmemb:要读取的数据元素的个数;
4、FILE* stream:指向要读取的文件的指针。
5、返回值:成功读取的元素个数。若读取成功,num>0;如果发生错误或者达到文件末尾,num<=0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>
typedef struct st_stu
{
char name[10];
int age;
float score;
}Stu;
int main()
{
Stu s[2] = {{"wy",18,99.9},{"ml",20,98.9}};
FILE* fp = fopen("10.txt","wb");
if (fp == NULL)
{
perror("文件打开失败");
return 1;
}
fwrite(s,sizeof(Stu),sizeof(s)/sizeof(Stu),fp);
fclose(fp);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>
typedef struct st_stu
{
char name[10];
int age;
float score;
}Stu;
int main()
{
Stu s[2] = {};
FILE* fp = fopen("10.txt","rb");
if (fp == NULL)
{
perror("文件打开失败");
return 1;
}
fread(s,sizeof(Stu),sizeof(s)/sizeof(Stu),fp);
printf("%s %d %.1f\n",s[0].name,s[0].age,s[0].score);
printf("%s %d %.1f\n",s[1].name,s[1].age,s[1].score);
fclose(fp);
return 0;
}

总结:使用场景

读写方式 应用场景 举例
字符 处理单个字符的场景 键盘读取
文本行 处理文本文件的场景 处理配置文件、日志文件、文本文档等
格式化 处理具有特定格式的数据的场景 比如将一个整数格式化为字符串、将字符串解析为浮点数等
数据块 处理二进制数据的场景 处理图像、音频、视频等二进制文件,以及网络传输中的数据块