接触C语言到现在,想必大家对通讯录的实现已经有所耳闻了吧,那么当程序运行结束,重新运行,上次运行的数据就会随程序结束释放,怎么才能保留数据让我们重复使用呢?
想要解决这个问题,你就要接着阅读下去,到篇尾,你或许茅塞顿开,吭哧吭哧的敲你的代码了
1. 文件指针
-
每个被访问的文件都会开辟一个相应的文件信息区,用来存放文件的相关信息(例如文件的名字、状态、位置)。这些信息被保存在一个结构体中,这个结构体的类型是系统声明的,取名FILE。
-
当你要读写一个文件时:
1.打开文件
2.被打开的文件维护了一个文件信息区
-
每当打开一个文件时,系统会根据文件的情况创建出一个FILE类型的变量,一般是通过FILE的指针来维护这个变量
-
FILE* pf; //文件指针变量
-
pf是一个指向FILE类型数据的指针变量,可以让pt指向某个文件的文件信息区,通过这个文件信息区就能访问该文件
2. 文件的打开与关闭
2.1 文件的打开
FILE* fopen(const char* filename, const char* mode);
- filename是要打开文件的路径,mode是操作指令,比如说你要是为了读文件啊还是写文件
- 返回的是文件信息区的地址,如果打开失败会返回NULL指针,因此执行该函数后需要即使判断是否打开失败,避免造成野指针
该图取自C技能树
2.2 文件的关闭
int fclose(FILE* stream);
- stream是指向文件的指针
- 若关闭失败返回EOF,成功返回0
FILE* pf = fopen("test.txt","w");//打开并读取文件
if(pf == NULL)//判断是否打开成功
{
perror("fopen");//提示打开失败的原因
return 1;
}
fclose(pf);//关闭文件
3. 文件的顺序读写(函数)
首先要链接程序什么情况下是读,什么情况下是写
3.1 fputc函数(字符输出)
int fputc ( int character, FILE * stream );
- 功能:向文件中写字符,指针向前进1,character是要写入的字符,stream是指向文件信息区的指针
- 写入成功,返回该字符的ASCII码值
- 写入失败,返回EOF
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputc('a', pf);
/*for (int i = 0; i < 10; i++)
{
fputc('a' + i, stdout);//stdout标准输出流,将内容展现在屏幕
}*/
fclose(pf);
return 0;
}
3.2 fgetc函数(字符输入)
int fgetc ( FILE * stream );
- 功能:读取文件中的字符(stream指向文件信息区),指针+1
- 返回读取到字符的ASSCII码值
- 读取失败返回EOF
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = fgetc(pf);//将从文件中读取到的字符返回给ch,此时pf已经指向下一个字符的位置
printf("%c\n", ch);
ch = fegetc(pf);
/*int arr[11] = { 0 };//利用stdin标准输入流读取键盘上输入的字符
for (int i = 0; i < 11; i++)
{
arr[i] = fgetc(stdin);
printf("%c", arr[i]);
}*/
fclose(pf);
return 0;
}
3.3 fputs函数(字符串输出)
int fputs ( const char * str, FILE * stream );
- 功能:写,将字符串写入到文件中,str是要写入字符串的首地址,stream是指向文件信息区的指针
- 成功返回非负值
- 失败返回EOF
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char arr[] = "asdasd";
fputs(arr, pf);
fclose(pf);
return 0;
}
3.4 fgets(字符串输入)
char * fgets ( char * str, int num, FILE * stream );
- 功能:向文件中读取num-1个字符拷贝到str中
- 若读取到\n换行符则停止,并且会将拷贝到的字符末尾追加一个\0
- 读取成功返回字符串
- 读取失败返回NULL
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char arr[10] = { 0 };
fgets(arr, 10, pf);
printf("%s\n", arr);
fclose(pf);
return 0;
}
3.5 fwrite函数(二进制写文件)
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
- 功能:从ptr指向的空间拷贝count个大小为size字节的内容给文件
- 返回实际写入的个数
int main()
{
FILE* pf = fopen("test.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int ret = fwrite(arr, sizeof(int), 10, pf);
printf("%d\n", ret);
fclose(pf);
return 0;
}
3.6 fread函数(二进制读文件)
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
- 功能:从文件中读取count个大小为size个字节的数据拷贝给ptr指向的空间
- 返回读取到元素的个数
int main()
{
FILE* pf = fopen("test.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int arr[10] = { 0 };
fread(arr, 4, 10, pf);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
fclose(pf);
return 0;
}
4. 文件随机读写
4.1 fseek函数
int fseek(FILE* stream, long int offset, int origin);
- offset是偏移的距离,origin是从哪里开始偏移
- origin有三个选择:
- SEEK_SET(文件起始位置)
- SEEK_CUR(文件当前位置)
- SEEK_END(文件末尾)
- 功能:从origin
- 给定的位置偏移offset个位置,读取字符,返回字符的ASCII码值
- 偏移:offset可正可负,是文件指针移动
4.2 ftell函数
long int ftell(FILE* stream);
功能:返回文件指针距离起始位置的偏移量
4.3 rewind函数
void rewind(FILE* stream);
功能:让文件指针的位置回到起始位置
5. 文件读取结束判断
- 不能用feof函数的返回值直接判断文件是否结束
feof的作用是在文件读取结束后,判断读取结束的原因是不是遇到文件尾结束 - 如何判断读取是否结束,判断返回值是不是EOF(fgetc),或者NULL(fgets)
例如:- fegetc判断是否为EOF
- fgets判断返回值是否为NULL
- 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数
fread判断返回值是否小于实际要读的个数
6. 文件缓冲区
当缓冲区的数据满了才会一起传送数据
或者刷新缓冲区即可,fclose就可以刷新缓冲区,这样可以保证关闭文件前数据不会丢失