文件操作
一、文件的打开与关闭
1.1对文件指针的理解
(1)缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。
(2)每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文 件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.
(3) 定义pf:pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。如图:
1.2文件的打开
对于文件的打开,我们需要用到”fopen“,而fopen的用法如下
FILE * fopen ( const char * filename, const char * mode );
1.3文件的关闭
文件的关闭相对的我们要用到 “fclose",fclose的用法如下
int fclose ( FILE * stream )
综上,我们根据fopen和fclose可以写出一个基本的文件打开和关闭,代码如下
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "w");// fopen打开文件,从内存中分配一块
if (NULL == pf)
{
perror("fopen");
return 1;
}
fclose(pf);
pf = NULL;
return 0;
}
1.4文件的打开方式
二、文件的顺序读写
2.1字符输入输出函数
字符输入函数的函数名为 fgetc 适用于所有输入刘流,而字符输出函数函数名为 fputc 适用于所有输出流。我们写文件的代码如下
//写文件
/*fputc('a', pf);
fputc('b', pf);
fputc('c', pf);*/
int i = 0;
for (i = 0; i < 26; i++)
{
fputc('a' + i, pf);
}// 这里是打印26个字母
读文件的时候我们要将开始的代码fopen中的w改成r,代码如下
//读文件
int ch = fgetc(pf);
printf("%c\n", ch);
它的返回值是正确的是int,如果返回失败的话,我们就要用另外一种更好的写法
int ch = 0;
while ((ch = fgetc(pf)) != EOF)
{
printf("%c ", ch);
}
2.2文本行输入输出函数
与字符输入输出类似,文本行输入输出用的是fgets和fputs。
一行一行写文件代码如下
(1)fputc:
// 写文件一行一行写
fputs("hello\n", pf);
fputs("woshihulianwangzhishen", pf);
在读一行行文件的时候,假设我打印的是10个数字,结果可能打印出9个数字再加上\0,代码如下
(2)fgetc:
// 一行一行读文件
char arr[] = "123456789";
fgets(arr, 20, pf);
printf("%s", arr);
fgets(arr, 20, pf);
printf("%s", arr);
2.3格式化输入输出函数
(1)写数据:当你想要将一个结构体写进一个文件中时,很显然前面介绍的fputc和fpits都无法实现,因而在这里我们引进一个概念叫格式化输入输出,也就是说要用到fprintf。事实上fprintf的用法和printf极其类似,在这里可以先看一下它的定义和用法
接着我们来进行代码的实现,代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { "zhangsan", 20, 95.5f };
// 把s中的数据写到文件中
FILE* pf = fopen("test.txt", "w");
if (NULL == pf)
{
perror("fopen");
return 1;
}
// 写文件
fprintf(pf, "%s %d %,1f", s.name, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}
这样在该程序文件中,就会出现一个test.txt文件,打开,成功写进去
(2)读取数据,我们用的是fscanf,代码如下:
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { 0 };
FILE* pf = fopen("test.txt", "r");
if (NULL == pf)
{
perror("fopen");
return 1;
}
// 读文件
fscanf(pf,"%s %d %f", s.name, &(s.age), &(s.score));
printf("%s %d %f\n", s.name, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}
2.4二进制的输入输出
(1)fwrite: 对于二进制的输入输出,与之前套路一样,我们利用的时fwrite,先来看看fwrite的定义:
这里写进第一个数应该是指针变量所给的地址。代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { "zhangsan", 20, 99.5f };
FILE* pf = fopen("test.txt", "wb");// wb二进制的写
if (NULL == pf)
{
perror("fopen");
return 1;
}
// 写文件
fwrite(&s, sizeof(s), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
我们再打开文件中的test记事本形式打开,能够看到:
之所以后面内容看不懂是因为这是用二进制写的。
(2) fread: 前面程序都一样,将wb改成rb,只是第二部分用fread来写。
通过观察fread的定义我们可以看到使用方法和fweite时一模一样的。主要代码如下:
int main()
{
struct S s = { 0 };
FILE* pf = fopen("test.txt", "rb");// rb二进制的读
if (NULL == pf)
{
perror("fopen");
return 1;
}
// 写文件
fread(&s, sizeof(s), 1, pf);
printf("%s %d %f\n", s.name, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}
我们价格运行结果打印出来,可以看到尽管用二进制写的问价我们并不认识,但是程序运行起来后还是能够识别的。
三、对输入输出流地理解
(1)对于任何一个C程序,只要运行起来,就默认打开3个流
3.1标准输入输出流
而这三个流在编译器上实现,可以这样写:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int ch = fgetc(stdin);
fputc(ch, stdout);
return 0;
}
// scanf(......)
// fscanf(stdin,.....)
// printf
// fprintf(stdout,.....)
3.2三者流的比较总结
3.2.1 scanf和printf
scanf:按照一定的格式从键盘输入数据
printf:按照一定的格式把数据打印(输出)到屏幕上
(适用于标准输入、输出流的格式化的输入/输出语句)
3.2.2 fscanf和fprintf
fscanf:按照一定的格式从输入流(文件/stdin)输入数据
fprintf: 按照一定的格式向输出流(文件/stdout)输出数据
(使用于所有的输入/输出流的格式化输入/输出语句
3.2.3 scanf和sprintf
sscanf:从字符串中按照一定的格式从读取出格式化的数据
sprintf: 把格式化的数据按照一定的格式转换成字符串
四、总结
以上大致就是大部分文件操作基本的用法和理解。当然C语言对文件的操作还有很多各种各样的用法。欢迎家人们在评论区指出文章中内容的不足,我会不断改进的。