C-文件操作

//序列化:将链表里的数据写入文件
//反序列化:将文件中的数据构建链表

//stdin:标准输入——》键盘 有缓冲区
//stdout:标准输出流——》屏幕
//stderr:标准出错流——》把错误信息输入到屏幕 无缓冲区

文件目录结构也叫B数结构

B/B+树是为了磁盘或其它存储设备而设计的一种平衡多路查找树(相对于二叉,B树每个内节点有多个分支),与红黑树相比,在相同的的节点的情况下,一颗B/B+树的高度远远小于红黑树的高度(在下面B/B+树的性能分析中会提到).B/B+树上操作的时间通常由存取磁盘的时间和CPU计算时间这两部分构成,而CPU的速度非常快,所以B树的操作效率取决于访问磁盘的次数,关键字总数相同的情况下B树的高度越小,磁盘I/O所花的时间越少.

文件操作格式:

在这里插入图片描述

文件操作函数

一.格式化函数

printf()将ptr指向的字符串格式化后打印到屏幕,底层调用了sprintf_s()

int printf(const char* ptr, ...);

sprintf_s()格式化字符串函数
将ptr指向的字符串格式化之后(格式成一个个字符)存入到buff中

int sprintf(char* buff, const char* ptr, ...);

VS2019中不支持sprintf(),因为不安全,数据可能将buff充爆,所以替换它的函数是sprintf_s()

int sprintf_s(char* buff, size_t buffcount,const char* ptr, ...);

fprintf()把任意类型的数据转换成字符串,并将格式化后的数据输入到指定的文件上面
//带缓冲区,先将文件写入缓冲区,等待关闭文件时(close(fp)才会将缓冲区数据写入fp指向的文件

int fprintf(FILE* fp, const char* ptr, ...);

二.打开文件函数

FILE* fopen(const char* filname, const char* mode);

在这里插入图片描述

VS2019将fopen进行了扩充fopen_s()
在这里插入图片描述

三.fopen()与fopen_s()的区别:

  • 返回值:
    fopen() :返回值是一个文件指针,若打开文件成功,返回一个指向该文件的文件指针,打开失败返回nullptr
    fopen_s():返回值是一个int类型
  • 参数:
    fopen_s(): 第一个参数是一个存放一级文件指针的指针,所以传入的参数是一级文件指针的地址。若文件打开失败,一级文件指针依旧为nullptr
 	FILE* fp = nullptr;
	//fp = fopen("C:/Users/86152/xsy/xsy.txt", "w");
	errno_t res = fopen_s(&fp, "C:/Users/86152/xsy/xsy.txt", "w");
	if (fp == nullptr)
	{
		printf("fopen file err %d\n", res);
		return 1;
	}
errno_t res = fopen_s(&fp, "C:/Users/86152/xsy/xsy.txt", "w");

fopen()建立的对象并不在用户区(栈区,数据区…),而是在内核区,由fp指向该空间,操作系统就会让该空间和磁盘或者硬盘中的某一个文件关联起来,若fp不为nullptr,则建立关系成功,fprintf()会将数据写入该内核对象指向的一块缓冲区,当程序执行fclose(fp),才会将缓冲区数据回写入磁盘中的文件。 然后将内核对象的引用计数降1为0,内核就会将该对象关闭,此时fp指向的内核对象没有了,fp就变成了失效指针
在这里插入图片描述

1.文本文件:

将数值转换成ASCLL码字符存放到文件中

在这里插入图片描述

2.二进制文件

内存中是什么格式原封不动在文件中就是什么格式

//二进制写文件函数
	fwrite(ar, sizeof(int), n, fp);//ar是缓冲区;每个元素的大小;需要写n个元素;写到fp指向的文件中
	

四.读取文件

数据都会先存放在缓冲区
在这里插入图片描述

scanf( “%d”,&a);// 从标准输入设备stdin读取数据给 a

sscanf( buff, “%d” ,&a );//从缓冲区buff中按%d 的格式读取数据给 a

fscanf( fp, “%d” ,&a);//从fp所指向的文件中读取数据给a

在这里插入图片描述

五.处理文本文件的函数

在这里插入图片描述

1.得到单个字符:getchar()与fgetc()

    char ch = '\0';
    scanf_s("%c",&ch);
	ch = getchar();//stdin
	//getchar()返回一个整型值,该函数从键盘获取到字符时将该字符的ASCLL码值给ch
	//等价于
	ch = fgetc(stdin);

2.得到字符串:gets_s()与fgets()

   //得到字符串,有效字符串个数n-1
	char buffa[128];
	char buffb[128];
	scanf_s("%s", buffa,128);//把空格当作输入结束符
	gets_s(buffa, 128);//返回值是一个指针,指向buffa的指针。将回车作为输入结束
//等价于
	fgets(buffb, 128, stdin);//将回车作为输入结束

3.将单个字符送到屏幕:putchar()

//将字符打印到屏幕
	const int n = 20;
	char ch = 'a';
	char stra[n] = { "yhping hello" };
	putchar(ch);putchar('\n');
	//等价于 printf("%c \n",ch);

4.将字符串送到屏幕:puts()

//将字符打印到屏幕
	const int n = 20;
	char ch = 'a';
	char stra[n] = { "yhping hello" };
	puts(stra);//将stra字符串送到屏幕,类似与printf(),但是printf()可以加'\n'
	puts("\n");

5.文件一次读一个字符:

char ch;
	FILE* fp = nullptr;
	errno_t res = fopen_s(&fp, "7.12文件操作.cpp", "r");
	if (fp == nullptr)
	{
		printf("fopen file err\n");
		return res;
	}
	// feof()判断是否到达文件末尾,若到达文件末尾返回为真,否则返回为假
	while (!feof(fp))//未到底文件末尾返回假,求反为真
	{
		ch = fgetc(fp);
		printf("%c", ch);
		Sleep(200);//每打印一个字符睡眠200ms
	}
	fclose(fp);
	fp = nullptr;
	return 0;

6.文件一次读一行:

char buff[10];//最多一次读9个字符
	FILE* fp = nullptr;
	errno_t res = fopen_s(&fp, "7.12文件操作.cpp", "r");
	if (fp == nullptr)
	{
		printf("fopen file err\n");
		return res;
	}
	// feof()判断是否到达文件末尾,若到达文件末尾返回为真,否则返回为假
	while (!feof(fp))//未到底文件末尾返回假,求反为真
	{
		fgets(buff, 10, fp);
		printf("%s", buff);
		Sleep(20);//每打印一个字符睡眠200ms
	}
	fclose(fp);
	fp = nullptr;
	return 0;

7.将一个文件打开,从该文件每读入一行,写入到新文件中:fgets()与fputs()

char buff[10];//最多一次读9个字符
	FILE* fp = nullptr;
	errno_t res = fopen_s(&fp, "7.12文件操作.cpp", "r");
	if (fp == nullptr)
	{
		printf("fopen file err\n");
		return res;
	}
	FILE* fw = nullptr;
	errno_t resw = fopen_s(&fw, "C:/Users/86152/xsy/xsy.txt", "w");
	if (fw == nullptr)
	{
		printf("fopen file err\n");
		return resw;
	}
	// feof()判断是否到达文件末尾,若到达文件末尾返回为真,否则返回为假
	while (!feof(fp))//未到底文件末尾返回假,求反为真
	{
		fgets(buff, 10, fp);
		fputs(buff,fw);
		Sleep(20);//每打印一个字符睡眠200ms
	}
	fclose(fp);
	fp = nullptr;
	return 0;

8.实现文件拷贝函数

int main(int argc, char* argv[])
{
	if (argc < 3)
	{
		printf("copy file error \n");
		//return 1;
		exit(EXIT_FAILURE);
	}
	//argv[1] srcfilename;原文件名
	//argv[2] destfilename;目标文件名
	FILE* fr = nullptr;//读文件
	FILE* fw = nullptr;//写文件
	//fr = fopen(argv[1], "r");
	errno_t rx = fopen_s(&fr, argv[1], "r");
	//fw = fopen(argv[2], "w");
	errno_t wx = fopen_s(&fw, argv[2], "w");
	if (fr == nullptr || fw == nullptr)
	{
		printf("open file failure \n");
		exit(EXIT_FAILURE);
	}
	char ch = '\0';
	while (!feof(fr))
	{
		ch = fgetc(fr);//从fr中读取一个字符给ch
		fputc(ch, fw);//把字符写入到fw中
		putchar(ch);//stdout
	}

	fclose(fr);
	fr = nullptr;
	fclose(fw);
	fw = nullptr;

	return 0;
}

六.主函数参数问题

1.不带参数

目的:程序运行过程中不希望从外界接收参数

int main()
{

}

2.带2个参数

程序运行过程中需要从外界获取参数
参数代表的意思:

  • argc:参数个数,包括当前运行的程序名称
  • argv[]:二级指针,存放外界传入参数的地址
int main(int argc,char*argv[])
{

}

在这里插入图片描述

3.带3个参数

参数代表的意思:

  • argc:参数个数,包括当前运行的程序名称
  • argv[]:二级指针,存放外界传入参数的地址
  • arge[]:存放环境变量
int main(int argc,char*argv[],char *arge[])
{

}

在这里插入图片描述

七.关于主函数形参的问题

在这里插入图片描述

1.argc,argv[]都是主函数形参,他们存在的空间都在主函数的栈帧里面,但是用户从键盘输入的形参(字符串)在哪里呢?

  • 代码区:不行,因为代码区编译链接后就已经固定了
  • 堆区:不行,因为需要malloc
  • 数据区:?
  • 栈区:?
    判断方法:
    可以打印形参地址。定义全局变量,打印全局变量地址空间;定义局部变量,打印局部变量地址空间;观察形参地址和哪个变量地址近,若和局部变量地址离的近,形参就在栈区;和全局变量地址离的近就在数据区。

2.输入的参数无论是字符,字符串,整型…主函数都按照字符串处理
用户输入:125.23.34.56==》主函数处理成:“125.23.34.56”
所以就需要将字符串解析成整型数据: atoi()

八.文件位置指针

打开文件时文件定位指针就在文件首

在这里插入图片描述
文件指针的特点:

  • 1.文本文件中:
    在文本文件中文件定位指针是无规律的,它是按照用户存放的数据值给出的位置信息,和数据在文本中的长度有关系
  • 2.二进制文件中:
    二进制文件在内存中是什么样子在文件中就是什么样子

1.文本文件形式实现

int main()
{
	const int n = 10;
	int ar[n] = { 12,23,34,45,1,234,2,345,5,8899};//数据长度不等
	FILE* fw = nullptr;
	errno_t err = fopen_s(&fw, "C:/Users/86152/xsy/ar.txt","w");
	if (fw == nullptr)
	{
		printf("open file error \n");
		exit(1);
	}
	for (int i = 0;i < n;++i)//向文件中写入数据
	{//     fw是文件流 
		fprintf(fw, "%d ", ar[i]);//将ar[i]中的数据写入fw指定的文件中,注意:此处只是写入到缓冲区,关闭文件才写入到文件
		 //       “%d " 是控制格式,每写入一个数据用空格隔开
	}
	fclose(fw);
	fw = nullptr;

	return 0;
}

在这里插入图片描述

ftell()实现文件位置定位

在这里插入图片描述
在这里插入图片描述

fell()返回值是long型—>4字节整型值,表示的范围是2G,即以该函数控制文件,文件大小最大为2G
fgetpos()使用ps作为文件定位指针,是unsigned long long ------->64字节,表示的文件范围就是2^64大小
在这里插入图片描述

int main()
{
	int val;
	const int n = 10;
	FILE* fr = nullptr;
	errno_t err = fopen_s(&fr, "C:/Users/86152/xsy/ar.txt", "r");
	if (fr == nullptr)
	{
		printf("open file error \n");
		exit(1);
	}
	int pos = ftell(fr);//获得文件位置信息
	while (!feof(fr))//判断文件是否到尾部
	{
		fscanf_s(fr, "%d", &val);//按照%d的格式将fr文件中的数据读到val中
		printf("val=%d ", val);
		pos = ftell(fr);
		printf("pos = %d \n", pos);
	}
	fclose(fr);
	fr = nullptr;

	return 0;
}

在这里插入图片描述

文本文件在文件中存放是按照数据对应的ASCLL码值存放的,由于数据是按照空格分隔存放,所以数据与数据之间有空格的ASCLL码值(20)
在这里插入图片描述

在文本文件中文件定位指针是无规律的,它是按照用户存放的数据值给出的位置信息,和数据在文本中的长度有关系

2.二进制文件形式实现

二进制文件在内存中是什么样子在文件中就是什么样子

在这里插入图片描述


//初始化二进制文件

int main()
{
	const int n = 10;
	int ar[n] = { 12,23,34,45,1,234,2,345,5,8899 };//数据长度不等
	FILE* fw = nullptr;
	errno_t err = fopen_s(&fw, "C:/Users/86152/xsy/bfile.txt", "wb");
	if (fw == nullptr)
	{
		printf("open file error \n");
		exit(1);
	}
	fwrite(ar, sizeof(int), n, fw);//将缓冲区ar中的数据,数据类型是整型,n个数据写入fw
	fclose(fw);
	fw = nullptr;

	return 0;
}

在这里插入图片描述

//二进制文件定位指针

int main()
{
	int val;
	const int n = 10;
	FILE* fr = nullptr;
	errno_t err = fopen_s(&fr, "C:/Users/86152/xsy/bfile.txt", "rb");
	if (fr == nullptr)
	{
		printf("open file error \n");
		exit(1);
	}
	int pos = ftell(fr);//获得文件位置信息
	/*fpos_t ps;
	fgetpos(fr, &ps);*/
	for(int i=0;i<n;++i)
	{
		fread(&val, sizeof(int), 1, fr);//从fr中每次读一个整型给val
		pos = ftell(fr);
		printf("val = %4d pos= %4d \n",val, pos);
	}
	fclose(fr);
	fr = nullptr;

	return 0;
}

在这里插入图片描述

二进制文件在内存中是什么样子在文件中就是什么样子

3. fseek()可以计算文件大小

在这里插入图片描述
在这里插入图片描述
计算文件大小并将文件内容写入buff 步骤:

  • 1.把文件以二进制方式打开
  • 2.设置文件指针在文件末尾
  • 3.读文件指针的位置(该位置就是文件的大小)
  • 4.堆上申请空间
  • 5.文件定位指针移动到文件首(fread()读数据是从文件首开始读的)
int main()
{
	FILE* fr = nullptr;
	errno_t err = fopen_s(&fr, "7.19File.cpp", "rb");
	if (fr == nullptr)
	{
		printf("open file error \n");
		exit(1);
	}
	fseek(fr, 0, SEEK_END);//文件定位指针直接偏移到末尾
	int len = ftell(fr) + 1;//文件定位指针的位置就是文件字节个数
	char* buff = (char*)malloc(sizeof(char) * len);
	if (buff == nullptr)
	{
		return 1;
	}
	rewind(fr);//fseek(fr, 0, SEEK_SET);

	fread(buff, sizeof(char), len, fr);
	buff[len - 1] = '\0';
	printf("%s", buff);
	fclose(fr);
	fr = nullptr;
	free(buff);
	buff = nullptr;

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值