【文件基本操作】
目录:
- 前言
- 一、什么是文件
- (一)程序文件
- (二)数据文件
- (三)文件名
- 二、文件的打开和关闭
- (一)文件指针
- (二)文件的打开和关闭
- 三、文件的顺序读写
- 四、文件的随机读写
- (一)fseek
- (二)ftell
- (三)rewind
- 五、文本文件和二进制文件
- 六、文件读取结束的判断
- 七、文件缓冲区
- 总结
前言
大家好,我们在平时练习代码时,一般都是,需要什么数据都从键盘进行输入,
练习的时候倒是没什么问题,可是,当我们需要输入大量数据的时候,
比如模拟实现一个通讯录,
关掉程序后数据就会消失,每次都需要从头开始输入,那使用这样的通讯录就会非常难受。
我们使用通讯录就是为了把信息记录下来,只有我们自己选择删除数据的时候,数据才不复存在。
这就涉及了数据持久化的问题,我们一般数据持久化的方法有:把数据存放在磁盘文件、
把数据存放到数据库等方式。
使用文件可以让我们将数据存放到电脑硬盘上,做到了数据的持久化。
一、什么是文件
磁盘上的文件就是文件。
但是在程序设计中,从文件功能的角度来分类可以分为两种:程序文件、数据文件
(一)程序文件
包括源程序文件,目标文件,以及可执行程序
(二)数据文件
文件中存放的是程序运行时读写的数据,比如从中读取数据的文件,或者输出内容的文件。
(三)文件名
一个文件要有唯一的文件标识,便于用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
例如:c:\vs 2022\test_10_13.txt
为了方便起见,文件标识常被称为文件名。
二、文件的打开和关闭
(一)文件指针
缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。
这些信息是保存在结构体变量中的。该结构体类型是由系统声明的,取名FILE。
不同的编译器对FILE结构体有不同的定义,在VS下,FILE结构体的成员如下:
typedef struct _iobuf
{
char* _ptr; //文件输入的下一个位置
int _cnt; //剩余多少个字符未被读取
char* _base; //基础位置(文件的起始位置)
int _flag; //文件标志
int _file; //文件的有效性验证
int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取
int _bufsize; //文件的大小
char* _tmpfname; //临时文件名
}FILE;
我们一般都是通过一个FILE指针来维护这个FILE结构的变量,这样使用起来更加方便。
示例:
FILE* pf;
变量pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件信息区(是一个结构体变量),通过文件信息区里的信息就可以访问到该文件。
示例:
(二)文件的打开和关闭
文件在读写之前都要进行打开,在使用结束之后应该关闭文件。
ANSIC规定使用fopen函数来打开文件,fclose函数来关闭文件。
函数原型:
FILE* fopen(const char* filename, const char* mode);
两个参数:一个为文件名,一个为打开方式
int fclose(FILE* stream);
一个参数:文件指针
打开方式如下:
三、文件的顺序读写
函数简介:
由于这部分内容介绍的十分详细,所以专门从本文中分了出来,大家可以通过本链接详细了解:C语言输入输出详解
四、文件的随机读写
(一)fseek
函数原型:
int fseek(FILE* stream, long int offset, int origin);
参数1:文件指针
参数2:偏移量
参数3:起点、源头
补充:参数3可以有三个值:
SEEK_SET 文件开头
SEEK_CUR 文件指针当前位置
SEEK_END 文件末尾
如果读取成功他将返回0,否则返回非0值,并且设置错误指示器。
示例:
int main()
{
FILE* pf = fopen("ppp.txt", "w");
char str[] = "The girl is very beautiful";
fputs(str, pf);
fclose(pf);
char s[60] = { 0 };
pf = fopen("ppp.txt", "r");
fgets(s, 30, pf);
puts(s);
putchar('\n');
fseek(pf, 17, SEEK_SET);
fgets(s, 30, pf);
puts(s);
fclose(pf);
return 0;
}
运行实例:
(二)ftell
long int ftell(FILE* stream);
返回文件指针的偏移量
示例:
int main()
{
FILE* pf = fopen("ppp.txt", "w+");
//以读和写的方式打开文件
char str[] = " I know. You know. I know that you know. I know that you know that I know.";
char tmp[100] = { 0 };
fputs(str, pf);
printf("文件指针偏移量:%ld\n", ftell(pf));
printf("此时从文件中进行读取数据:\n");
fgets(tmp, 100, pf);
puts(tmp);
printf("设置指针指向偏移量为0的位置\n");
fseek(pf, 0, SEEK_SET);
printf("再次读取数据:\n");
fgets(tmp, 100, pf);
puts(tmp);
fclose(pf);
return 0;
}
运行实例:
(三)rewind
函数原型:
void rewind(FILE* stream);
让文件指针的位置回到文件的起始位置。
示例:
int main()
{
FILE* pf = fopen("ppp.txt", "w+");
char str[3][100] = {" I know. You know." , " I know that you know."," I know that you know that I know."};
char tmp[100] = { 0 };
fputs(str[0], pf);
fputs(str[1], pf);
fputs(str[2], pf);
printf("文件指针偏移量:%ld\n", ftell(pf));
printf("此时从文件中进行读取数据:\n");
fgets(tmp, 100, pf);
puts(tmp);
printf("令文件指针指向文件起始位置\n");
rewind(pf);
//fseek(pf, 0, SEEK_SET);
printf("再次读取数据:\n");
fgets(tmp, 100, pf);
puts(tmp);
//结论:'\0'不会被读取进入
fclose(pf);
return 0;
}
运行实例:
五、文本文件和二进制文件
根据数据的组织形式,数据文件又分为文本文件和二进制文件。
数据在内存中的存储形式都为二进制,如果不加转换得输出到外存,就是二进制文件。
那数据在内存中是怎么存储的呢?
字符在内存中一律以ASCII码形式存储,数字型数据可以以ASCII形式存储也可以使用二进制形式存储。
如数字10000,
以ASCII形式输出到磁盘,则需要占用5个字节(一个字符占一个字节),
而以二进制形式输出到磁盘,则需要占用4个字节。
示例:
int main()
{
int con = 10000;
FILE* pf = fopen("ppp.txt", "wb");
fwrite(&con, sizeof(int), 1, pf);
//以二进制形式写入
fclose(pf);
return 0;
}
运行实例:
六、文件读取结束的判断
在从文件读取数据时,我们会遇到出错的情况,
这里可能会是读取到了文件的末尾,也有可能是读写过程出错了;
这是我们可以使用两个函数feof和ferror进行判断,
feof为eof指示器,当读取到文件末尾返回时,就会设置该指示器进行提醒。
ferror为错误指示器,如果是读写过程出错,就会设置该指示器。
函数原型:
int feof(FILE* _Stream);
int ferror(FILE* _Stream);
示例:
int main()
{
FILE* fp = fopen("ppp.txt", "w+");
if (fp == NULL)
{
perror("main::fopen");
return -1;
}
char ch = 0;
char str[] = "hello";
fputs(str, fp);
rewind(fp);
while ((ch = fgetc(fp)) != EOF)
{
putchar(ch);
}
if (feof(fp))
{
printf("\nEnd of file reached successfully\n");
}
else
if (ferror(fp))
{
printf("\nI / O error when reading\n");
}
fclose(fp);
return 0;
}
运行实例:
七、文件缓冲区
ANSIC标准采用“缓冲文件系统”来处理数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先将数据送到内存中的文件缓冲区,等到缓冲区充满后才一起写到磁盘上;从磁盘中读取数据也会先将数据输入到文件缓冲区,之后再将数据一一存入程序数据区(变量)。缓冲区的大小由c编译器决定。
验证:
#include<stdio.h>
#include<windows.h>
int main()
{
FILE* fp = fopen("ppp.txt", "w+");
if (fp == NULL)
{
perror("main::fopen");
return -1;
}
char ch = 0;
char str[] = "hello";
fputs(str, fp);
printf("字符串内容输入到文件缓冲区\n");
Sleep(10000);
//休息十秒
fclose(fp);
printf("刷新文件缓冲区\n");
return 0;
}
运行实例:
补充:我们在向文件中写入数据之后需要刷新文件缓冲区或者关闭文件,否则可能会在会出现问题。
总结
以上就是我们文件部分的全部内容,如果有什么疑问或者建议都可以在评论区留言,感谢大家的支持,欢迎来评论区一起探讨,大家的鼓励是继续更新的巨大动力。