文件操作2+程序的编译和链接(1)

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在关闭文件的时候会刷新缓冲区

相关推荐
Tony_yitao3 小时前
12.华为OD机试 - N个选手比赛前三名、比赛(Java 双机位A卷 100分)
java·算法·华为od·algorithm
西西学代码3 小时前
Flutter中常用的UI设计
前端·flutter·ui
std860213 小时前
Linux 6.18发布:年度最后版本或成新长期支持版本
linux·运维·服务器
HalvmånEver3 小时前
Linux:进程替换(进程控制四)
linux·运维·服务器·学习·进程
Sunhen_Qiletian3 小时前
《Python开发之语言基础》第七集:库--时间库
前端·数据库·python
一叶之秋14123 小时前
从零开始学Linux进程控制:fork、wait、exec 详解
linux·运维·服务器
JokerLee...3 小时前
【Vtable自定义样式】
前端·javascript·vtable
老华带你飞3 小时前
医院挂号|基于Java医院挂号管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot
PyHaVolask3 小时前
XSS跨站脚本攻击
前端·xss·web漏洞