1.为什么使用文件
因为我们想记录数据,在内存中的数据当设备重启就会消失,而存放在硬盘里面就不会消失,从而做到了数据的持久化
2.什么是文件
文件是计算机系统中存储数据的基本单位,从功能角度大概可以分为两类文件
- 程序文件:可执行文件,例如.c文件.cpp文件.exe文件
- 数据文件:存放数据的文件,可以是文本文件,也可以是二进制文件
- 文件名:用来标识一个文件的唯一性,由文件路径,文件名和后缀构成
3.文件的打开和关闭
每一个被使用的文件都会在内存里面创建一个文件信息区,该文件信息区包含该文件的所有信息,文件名,文件内容,文件位置等等,它们都存放在一个由系统声明的一个结构体中,名字叫做FILE
所以我们创建一个文件变量指针,就能找到与之关联的文件
每个文件对应的文件信息区是各不相同的
我们使用fopen来打开文件,fcolse来关闭文件
FILE * fopen ( const char * filename, const char * mode );int fclose ( FILE * stream );
常见的打开方式有
4. 文件的顺序读写
4.1 顺序读写函数介绍
这些函数在c++网站上均可以查到使用方法,就不在这里赘述了
我们来介绍一下什么是流
流:类似于水流,我们可以理解一下,这里的流指的是数据流
在C语言中我们常见的有标准有
- 标准IO流:标准输入流(stdin)、标准输出流(stdout)和标准错误流(stderr)
- 文件IO流:文件输入流(File input stream)和文件输出流(File output stream)
还有一个概念,什么叫做输入,什么叫做输出
大概可以这样表示
4.2对比一组函数
如果你有兴趣,可以研究一下下面的函数
scanf/fscanf/sscanf
printf/fprintf/sprintf
#include <stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//操作文件
int arr[10] = {1,2,3,4,5};
int i = 0;
for (i = 0; i < 10; i++)
{
fprintf(pf, "%d", arr[i]);
}
fclose(pf);
pf = NULL;
return 0;
}
5. 文件的随机读写
5.1 fseek
int fseek ( FILE * stream, long int offset, int origin );
该函数的作用是:Reposition stream position indicator也就是重新定位流位置指示器
offset是需要偏移几个字节
origin是选择这三项:SEEK_SET、SEEK_CUR、SEEK_END,也就是文件的开头,当前的位置和,文件结束的位置
举个栗子
#include <stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w+");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//操作文件
char c=0;
fputs("abcdef", pf);
rewind(pf);
fseek(pf, 2, SEEK_SET);
c=fgetc(pf);
printf("%c", c);
fseek(pf, 0, SEEK_CUR);
c = fgetc(pf);
printf("%c", c);
fseek(pf, -4, SEEK_END);
c = fgetc(pf);
printf("%c", c);
fclose(pf);
pf = NULL;
return 0;
}
5.2 ftell
long int ftell ( FILE * stream );
该函数的作用是:Get current position in stream也就是获取流中的当前位置
#include <stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w+");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//操作文件
int i=0;
fputs("abcdef", pf);
rewind(pf);
fseek(pf, 2, SEEK_SET);
i = ftell(pf);
printf("%d ", i);
fseek(pf, 0, SEEK_CUR);
i = ftell(pf);
printf("%d ", i);
fseek(pf, -4, SEEK_END);
i = ftell(pf);
printf("%d", i);
fclose(pf);
pf = NULL;
return 0;
}
5.3rewind
void rewind ( FILE * stream );
该函数的作用是:Set position of stream to the beginning也就是设置流的起始位置
#include <stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w+");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//操作文件
int i=0;
fputs("abcdef", pf);
fseek(pf, -4, SEEK_END);
i = ftell(pf);
printf("%d ", i);
fgetc(pf);
i = ftell(pf);
printf("%d ", i);
rewind(pf);
i = ftell(pf);
printf("%d ", i);
fclose(pf);
pf = NULL;
return 0;
}
6. 文本文件和二进制文件
现在我们用写的方式打开一个文件,并给它里面放一些二进制的内容
我们看当前目录确实出现了一个text.txt文件,里面的内容是二进制代码
我们是用二进制方式打开
根据数据的组织形式,可以分为二进制文件和文本文件
- 数据在内存中以二进制形式存储,如果不加转换就放入外存,就是二进制文件
- 数据如果在存储之前转化为ASCII码再放入外存,那么就属于文本文件。
7. 文件读取结束的判定
7.1 被错误使用的feof
int feof ( FILE * stream );
该函数的作用是判断当文件读取结束时,使用feof来判断文件是以什么方式结束的
fgetc结束时返回EOF,fgets结束时返回NULL,fread结束时返回一个整型
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int c = 0;
FILE* pf = fopen("data.txt", "w+");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//操作文件
const char *arr = "abcdef";
fputs(arr, pf);
rewind(pf);
while ((c=fgetc(pf) )!= EOF)
{
putchar(c);
}
printf("\n");
if (ferror(pf))
{
printf("读取时发生错误\n");
}
else if(feof(pf))
{
printf("文件成功读取到结束\n");
}
fclose(pf);
pf = NULL;
return 0;
}