📄 4-linkfileautowr.cpp
字号:
/*
作者: 李洋
创建时间: 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 + -