⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 4-linkfileautowr.cpp

📁 首先在程序中生成插入数据,可以随机插入也可以手动插入,然后自动生成索引文件,查找数据的时候可以根据索引来查找.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
作者:		李洋
创建时间:	2008.03.27
最后修改:	2008.04.10
联系方式:	leeocean2004@163.com
程序说明:	完整版写入链表文件
往文件clientFile.dat文件中插入数据的同时,在索引文件linkFileIndex.ind中予以管理,并附自动生成需要的条数的
链表文件等功能
*/

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include <string.h>

#define	MAXDATA	3000000					//事先准备好的数据文件中的文件数,前面生成了300条,编号从1到300,若MAXDATA超过32727要调整
#define DH	sizeof(dataHead)		//数据头文件的长度
#define DN	sizeof(dataNode)		//数据文件长度
#define IH	sizeof(indexHead)		//索引头文件文件长度
#define IN	sizeof(indexNode)		//索引结点长度

int		num;						//有效数据数,全局变量
int		phyNum;						//数据文件内所有数据项的条数,全局变量

//--------------------------------------------------------------------------------所有数据结构体声明
//1.数据头结点
typedef struct
{
	int		phyNum;		//数据文件中数据条目个数(不一定就是有效节点数)
	int		count;		//有效数据数
}dataHead;

//2.数据结点
typedef struct
{
	int		account;		//帐号
	char	name[32];		//帐户名
	double	balance;		//帐号余额
	char	other[464];		//其它附加信息
}dataNode;

//3索引头结点
typedef struct
{	
	int headNext;		//代表下一条数据指针
}indexHead;

//4索引结点
typedef struct
{
	int primaryKey;		//关键字
	int addr;		//关键字所在位置
	int next;		//关键字next所在的位置
}indexNode;

//5文本文件-姓名数据
typedef struct
{
	int no;		//编号
	char name[32];		//姓名
}nameNode;

//6文本文件-说明
typedef struct
{
	int no;		//编号
	char other[464];		//说明
}otherNode;
//--------------------------------------------------------------------------------函数声明
int		enterChoice();							//0		菜单
int		readDataFileEffectNum(FILE *);			//1		读取数据文件头,num
int		readDataFilePhysicalNum(FILE *f);		//2		读取物理路意义上数据个数,phyNum
int		readIndexFileHead(FILE *);				//3		读取索引文件头
void	writeDataFileHead(FILE *,int,int);		//4		写数据文件头
void	writeIndexFileHead(FILE *,int);			//5		写索引文件头
void	writeDataFile(FILE *,dataNode *,int);	//6		写数据
void	writeIndexFile(FILE *,indexNode *,int);	//7		写索引
int		adjust(FILE *,indexNode);				//8		调整
void	readAllDataFile(FILE *);				//9		读取数据(物理方式)
void	readAllIndexFile(FILE *);				//10	读取索引数据
void	readDataByIndex(FILE *,FILE *);			//11	读取数据(索引方式)
void	deleteData(FILE *,FILE *,int);			//12	删除数据
void	clear(FILE *,FILE *);					//13	清空数据
int		insert(FILE *,FILE *,dataNode);			//14	插入数据
void	aotoWork(FILE *,FILE *,FILE *,int);		//15	自动生成链表文件
void	searchN(FILE *,FILE *,int);				//16	查找数据

//**********************************************************************************************************************
//												        主函数
//**********************************************************************************************************************
void main()
{
	FILE		*dp;		//指向数据文件的指针
	FILE		*ip;		//指向索引文件的指针
	FILE		*sp;		//资源文件
	dataNode	newData;	//存放数据结点	
	int			choice;		//菜单选项
	int			deleteNum;	//要删除的帐号
	int			autoNum;	//自动生成链表数据个数
	int			searchNum;	//要查找帐号
	int			maxNum;
	
	dp=fopen("dataFile.dat","rb+");			//打开数据文件
	ip=fopen("indexFile.dat","rb+");		//打开索引文件
	
	
	//若第一次运行程序定义数据文件的头是0,0(0个有效数据,0个物理数据),同时定义索引文件的头指向-1
	if(readDataFileEffectNum(dp)<0)		//如果是空文件打开时候读取到的是一个乱码但是小于0
	{
		phyNum=0;		//物理数据数
		num=0;		//有效数据数
		writeDataFileHead(dp,0,0);		//写数据文件头
		writeIndexFileHead(ip,-1);		//写索引文件头
	}
	else
	{
		num=readDataFileEffectNum(dp);		//给全局变量赋值
		phyNum=readDataFilePhysicalNum(dp);		//给全局变量phyNum赋值
	}
	printf("---打开数据文件,当前数据文件中有%d条有效数据,总共%d条数据---\n",num,phyNum);
	
	
	while((choice=enterChoice())!=0)
	{
		switch(choice)
		{			
		case 1:		//14
			//输入信息,输入ctrl+z结束输入,获得一个数据节点newData
			printf("请输入客户的帐号、姓名、余额、用户说明信息(输入ctrl+z则停止输入)\n>>");
			fscanf(stdin,"%d%s%lf%s",&newData.account,newData.name,&newData.balance,newData.other);	
			while(!feof(stdin))		
			{		
				insert(dp,ip,newData);		// 14 往数据文件dp,索引文件ip中插入新数据newData
				printf("请输入客户的帐号、姓名、余额、用户说明信息\n>>");
				fscanf(stdin,"%d%s%lf%s",&newData.account,newData.name,&newData.balance,newData.other);	
			}	
			break;
			
		case 2:		//8
			printf("按物理路径读取全部数据文件:\n");
			readAllDataFile(dp);
			break;
			
		case 3:		//10
			printf("根据索引读取数据:\n");
			readDataByIndex(dp,ip);
			break;
			
		case 4:		//9
			printf("读取全部索引文件:\n");
			readAllIndexFile(ip);
			break;	
			
		case 5:		//11
			printf("删除数据:\n输入要删除帐号\n>>");
			scanf("%d",&deleteNum);
			deleteData(ip,dp,deleteNum);
			break;	
			
		case 6:		//15
			maxNum=(MAXDATA-num);
			printf("自动生成链式文件:\n想要生成多少项数据(1 ~ %d条)\n>>",maxNum);
			scanf("%d",&autoNum);
			if(autoNum>(maxNum)||autoNum<1)		//范围控制
			{
				printf("输入范围有错,生成失败!");
				break;
			}
			sp=fopen("dataSource.dat","rb");
			aotoWork(dp,ip,sp,autoNum);
			break;	
			
		case 7:		//16
			printf("查找:\n请输入想要查找的帐号\n>>");			
			scanf("%d",&searchNum);
			searchN(ip,dp,searchNum);
			break;
			
		case 8:		//13		
			clear(dp,ip);
			printf("已经把数据文件和索引文件中的所有数据全部清除!\n");
			break;
			
		default:
			printf("退出\n");
			break;
		}	//结束switch
	}	//结束while
	
	printf("关闭数据文件和索引文件.\n");
	fclose(dp);
	fclose(ip);	
}

//*****************************************函数定义********************************************
//*****************************************函数定义********************************************
//--------------------------------------------------------------------------------0	用户菜单
//用户输入菜单选项
int enterChoice()
{
	int	menuChoice;		//存储用户选项的变量
	printf("\n当前数据文件中有%d条有效数据,总共%d条数据---\n",num,phyNum);
	printf("\n输入你的选择:\n"
		"1: 插入数据   "
		"2: 顺序读取   "
		"3: 索引读取   "
		"4: 读取索引\n"
		"5: 删除数据   "
		"6: 自动生成   "
		"7: 数据查找   "
		"8: 清空数据   "
		"0: 退出\n请选择>>");
	
	//从用户处获得选项
	scanf("%d",&menuChoice);	
	return menuChoice;
}	//结束enterChoice函数

//--------------------------------------------------------------------------------1	读数据文件头,返回有效数据数
/*
具体说明:	
数据文件默认已经打开,返回一个整数head.effectNum表示当前数据文件中包含的有效数据个数,如果没有返回0.
*/
int readDataFileEffectNum(FILE *f)
{	
	if(f!=NULL)
	{
		dataHead head;		//头结点
		rewind(f);
		fread(&head,DH,1,f);
		return(head.count);
	}
	else
	{
		printf("读数据文件头时文件打开失败! (error 1.) \a\n");
		return -1;
	}
}
//--------------------------------------------------------------------------------2	读数据文件头,返回物理数据数
int readDataFilePhysicalNum(FILE *f)		//读取物理上文件含有的所有物理数据个数head.phyNum
{
	if(f!=NULL)
	{
		dataHead head;		//头结点
		rewind(f);
		fread(&head,DH,1,f);
		return(head.phyNum);
	}
	else
	{
		printf("读数据文件头时文件打开失败! (error 2.) \a\n");
		return -1;
	}
}	//end main()
//--------------------------------------------------------------------------------3	读索引文件头
/*
具体说明:
默认索引文件已经打开,返回一个整数head.headNext,代表头所指向的最小的一条数据的索引的位置.
*/
int readIndexFileHead(FILE *f)
{	
	if(f!=NULL)
	{
		indexHead head;		//索引文件头
		rewind(f);
		fread(&head,IH,1,f);
		return(head.headNext);
	}
	else																	
	{
		printf("读索引文件头时文件打开失败! (error 3.) \a\n");
		return -1;
	}
}

//--------------------------------------------------------------------------------4	写数据文件头
/*
具体说明:
参数3个:数据文件的指针,有效数据数,物理数据数.如果文件打开了,则把头写进去,否则显示写入失败.

*/
void writeDataFileHead(FILE *f,int eff,int phy)
{	
	dataHead h;		//数据头文件结点
	if(f!=NULL)
	{		
		h.count=eff;
		h.phyNum=phy;
		rewind(f);
		fwrite(&h,DH,1,f);	
	}
	else
	{
		printf("写数据文件头时文件未被打开. 写入失败! (error 4.) \a\n");
	}
}
//--------------------------------------------------------------------------------5	写索引文件头
/*
具体说明:
参数2个:数据文件指针,代表地址的整数.整数代表一条数据的指针.一般这条数据就是当前最小的一个索引的地址.如果写入失败给予提示
*/
void writeIndexFileHead(FILE *f,int addr)		//注意这里n直接就是地址,而不是单元数
{	
	indexHead head;
	if(f!=NULL)
	{		
		head.headNext=addr;
		rewind(f);
		fwrite(&head,IH,1,f);	
	}
	else
		printf("写索引文件头时文件未打开. 写入失败! (error 5.) \a\n");
}
//--------------------------------------------------------------------------------6	写数据结点
/*
具体说明:
打开数据文件f,把节点dn写到第c个位置(c=0,1,2...)
*/
void writeDataFile(FILE *f,dataNode *dn,int c)		//注意这里c代表单元数,而且dataNode用的是指针
{
	if(f!=NULL)
	{
		fseek(f,c*DN+DH,SEEK_SET);
		fwrite(dn,DN,1,f);			
	}
	else
		printf("写数据文件时文件打开失败! (error 6.) \a\n");
}
//--------------------------------------------------------------------------------7	写索引结点
/*
具体说明:
打开索引文件,把节点dn写入到第c+1个单元
*/
void writeIndexFile(FILE *ifp,indexNode *dn,int c)		//注意这里c是单元数
{
	if(ifp!=NULL)
	{
		fseek(ifp,c*IN+IH,SEEK_SET);
		fwrite(dn,IN,1,ifp);
	}
	else
		printf("写索引文件时文件打开失败! (error 7.) \a\n");		
}
//--------------------------------------------------------------------------------8	调整并写入索引
/*
具体说明:
调整的作用,如果可以插入把新的索引数据i的next修改之后然后写入到索引文件ipf中,并返回1,否则不将索引项写入索引文件返回0
*/
int adjust(FILE *ifp,indexNode i)		//若成功调整索引文件前面的数据然后新索引i写到索引文件返回1,否则什么也不错返回0
{
	indexHead	iHead;
	indexNode	pre;
	indexNode	curr;	
	int			preAddr;	//新结点前面节点的地址
	
	if(ifp!=NULL)		//索引文件能打开
	{		
		//读取索引的头文件,存放在iHead中
		rewind(ifp);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -