

fprintf
cpp
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { 0 };
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文
fprintf(pf,"%s %d %f", s.name, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}
fscanf
cpp
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { 0 };
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文
fscanf(pf,"%s %d %f", s.name,&(s.age) , &(s.score));
//
printf( "%s %d %f", s.name, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}

cpp
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { 0 };
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文
fscanf(pf,"%s %d %f\n", s.name,&(s.age) , &(s.score));
//打印在屏幕上
//printf( "%s %d %f", s.name, s.age, s.score);
fprintf(stdout, "%s %d %f\n", s.name, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}
对于futc
{
cpp
int main()
{
fputc('a', stdout);
return 0;
}
所以这些函数不只是在文件里输入和输出,还可以对应在屏幕上,对应标准输出stdout
对比一组函数
scanf-从标准输入流上读取格式化的数据
fscanf_从所有输入流上读取格式化的数据
sscanf在字符串中读取格式化的数据
printf-把数据以格式化的形式打印在标准输出流上
fprintf-把数据以格式化的形式打印在指定的输出流上
sprintf把格式化的数据转换成字符串
cpp
struct S
{
char name[20];
int age;
float a;
};
int main()
{
char buf[200] = { 0 };
struct S s = { "张三",20,65.5f };
sprintf(buf,"%s %d %f", s.name, s.age, s.a);
printf("%s\n", buf);
struct S t = { 0 };
sscanf(buf, "%s %d %f", t.name, &(t.age), &(t.a));
printf("%s %d %f\n", t.name,t.age,t.a);
return 0;
}

fread和fwrite
以二进制的形式输入和输出,适用于文本输入流

以二进制的方式写进
cpp
int main()
{
int arr[10] = { 0 };
FILE* pf = fopen("test.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fwrite(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);
//以二进制的形式写进去
fclose(pf);
pf = NULL;
return 0;
}

以二进制的方式读取

和fwrite反过来,以二进制的方式去读取
返回的是成功读取的元素的总个数
cpp
int main()
{
int arr[10] = { 0 };
FILE* pf = fopen("test.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int sz = sizeof(arr) / sizeof(arr[0]);
fread(arr, sizeof(arr[0]), sz, pf);
//以二进制的形式写进去
int i = 0;
for (i; i < sz; i++)
{
printf("%d ", arr[i]);
}
fclose(pf);
pf = NULL;
return 0;
}

返回的是成功读取的元素的总个数
换一种写法一次读取一个
cpp
int main()
{
int arr[10] = { 0 };
FILE* pf = fopen("test.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int i = 0;
while (fread(arr+i, sizeof(arr[0]), 1, pf))//一次读取一个整形//arr+i可以换&arr[i]
{
printf("%d ", arr[i]);
}
//以二进制的形式写进去
fclose(pf);
pf = NULL;
return 0;
}
这里换成&arr[i]
{
cpp
int main()
{
int arr[10] = { 0 };
FILE* pf = fopen("test.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int i = 0;
while (fread(&arr[i], sizeof(arr[0]), 1, pf))//一次读取一个整形//arr+i可以换&arr[i]
{
printf("%d ", arr[i]);
}
//以二进制的形式写进去
fclose(pf);
pf = NULL;
return 0;
}
没有i++也能成功他打印的原因是读取一个打印一个,全放在arr[0]上了,因为读取也会一个一个往后读取----顺序读写
加上i++
文件的随机读写
fseek
根据文件指针的位置和偏移量来定位文件指针

origin起始位置:(有三个选择)
SEEK_SET 文件的起始位置
SEEK_CUR 文件至臻当前的位置
SEEK_END 文件末尾

cpp
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror(fopen);
return 1;
}
//读文件
int ch = fgetc(pf);
printf("%c\n", ch);
fseek(pf, 4, SEEK_CUR);
ch = fgetc(pf);
printf("%c\n", ch);
fclose(pf);
pf = NULL;
return 0;
}

ftell返回文件指针相对起始位置的偏移量
cpp
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror(fopen);
return 1;
}
//读文件
int ch = fgetc(pf);
printf("%c\n", ch);
fseek(pf, 4, SEEK_CUR);
int a = 0;
a = ftell(pf);
printf("%d", a);
fclose(pf);
pf = NULL;
return 0;
}
想计算文件的长度
可以使用
cpp
fseek(pf,0,SEEK_END);
printf("%d",ftell(pf));
rewink
让文件指针的位置回到文件的起始位置
cpp
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror(fopen);
return 1;
}
//读文件
int ch = fgetc(pf);
printf("%c\n", ch);
fseek(pf, 4, SEEK_CUR);
int a = 0;
a = ftell(pf);
printf("%d\n", a);
rewind(pf);
ch = fgetc(pf);
printf("%c\n", ch);
fclose(pf);
pf = NULL;
return 0;
}
文件读取结束的判定
1.被错误使用的 feof
牢记:文件现在读取结束了
但是是什么原因读取结束的
1.有可能是遇到文件末尾 feof
2.读取的时候发生了错误 ferror
打开一个流的时候;
这个流上有两个标记值:
1.是否遇到文件末尾
2.是收发生错误
对于文件是怎么判断读取结束的
判断返回值是否为EOF,或者NULL
比如fgetc,如果的确正常的话,返回字符的ASCLL值,如果读取异常的(遇到文件末尾或者错误)返回EOF
通过判断返回是不是EOF.来判断是否结束
fgets,读取正常的话返回读取到的字符错的地址。文件读取异常遇到文件末尾返回null
判断返回值是不是空指针
对于二进制文件的读取的结束,判断返回值是否小于实际要读的个数
cpp
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror(fopen);
return 1;
}
int ch = 0;
while ((ch = fgetc(pf)) != EOF)
{
printf("%c ", ch);
}
//如果ch=EOF,判断是什么原因导致的
if (feof(pf))//feof函数的本质返回的是int,如果返回的1,就是遇到文件末尾
{
printf("遇到文件末尾,读取正常结束");
}
else if (ferror(pf))
{
perror("fgetc");//看是什么错误
}
return 0;
}
对于二进制类似
拷贝文件的本质
int main()
{
return 0;
}
cpp
int main()
{
FILE* ptrin = fopen("test1.txt", "r");
if (ptrin == NULL)
{
perror("fopen:test1.txt");
return 1;
}
FILE* ptrout = fopen("test2.txt", "w");
if (ptrout == NULL)
{
perror("fopen:test2.txt");
fclose(ptrin);
return 1;
}
int ch = 0;
while ((ch = fgetc(ptrin)) != EOF)
{
fputc(ch, ptrout);
}
fclose(ptrin);
ptrin = NULL;
fclose(ptrout);
ptrout = NULL;
return 0;
}
文件缓冲区
内存中的程序并非直接写入在硬盘的文件
是先写在内存的文件缓冲区
ANSIC 标准采⽤"缓冲⽂件系统" 处理的数据⽂件的,所谓缓冲⽂件系统是指系统⾃动地在内存中为
程序中每⼀个正在使⽤的⽂件开辟⼀块"⽂件缓冲区"。从内存向磁盘输出数据会先送到内存中的缓
冲区,装满缓冲区后才⼀起送到磁盘上。如果从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输 ⼊到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓 冲区的⼤⼩根据C编译系统决定的。

cpp
#include <stdio.h>
#include <windows.h>
//VS2019 WIN11环境测试
int main()
{
FILE*pf = fopen("test.txt", "w");
fputs("abcdef", pf);//先将代码放在输出缓冲区
printf("睡眠10秒-已经写数据了,打开test.txt⽂件,发现⽂件没有内容\n");
Sleep(10000);
printf("刷新缓冲区\n");
fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到⽂件(磁盘)
//注:fflush 在⾼版本的VS上不能使⽤了
printf("再睡眠10秒-此时,再次打开test.txt⽂件,⽂件有内容了\n");
Sleep(10000);
fclose(pf);
//注:fclose在关闭⽂件的时候,也会刷新缓冲区
pf = NULL;
return 0;
}
1
fclose在关闭文件的时候会刷新缓冲区