c++文件增删改查信息

文件增删改查信息

  • 前言
  • mian.cpp
  • Select类--内存中提供增删改查 功能等
    • Select类源码.h
    • Select类源码.cpp

前言

  • 用来自我加强练习

  • 之后增加–优化封装一个文件类

  • 自我记录一下

mian.cpp

#include 
#include 
//#include  // 
#include "Select.h"
#include 
//#include "ClassPone.h"
#define Write_Error -1
#define Read_Error -2
fstream fs;
/*
	* InsertFileDate
	* 参数一:pPhoneNumber 用户结构体指针
	* 参数二:Phone 管理用户信息类指针
	* 功能  : 往文件尾部新增一个用户信息数据
	* 返回值 :int  成功返回0 失败-1
*/
int InsertFileDate(pPhoneNumber pTempPhone, Select* Phone);

/*
	* DeleteFileDate
	* 参数一:FileOffset 用户在文件中的储存偏移
	* 功能  :删除一个用户信息
	* 返回值 :int  成功返回0 失败-1
*/
int DeleteFileDate(unsigned FileOffset);



/*
	* WriteFileAllDate
	* 参数一:Select类指针
	* 功能  :把内存中的数据写入文件中
	* 返回值 :int  成功返回0 失败-1
*/
int WriteFileAllDate(Select* Phone);


/*
	* InitReadDate
	* 参数一:无
	* 功能  :把文件数据读取到指定内存中
	* 返回值 :类Select指针
*/
Select* InitReadDate();
/*
	* InitReadDate
	* 参数一:无
	* 功能  :把文件数据读取到指定内存中
	* 返回值 :类Select指针
*/
Select* InitReadDate();

int main()
{
	//in 读取里面的内容   out 像里面输出内容
	//打开文件
	Select* Phone = InitReadDate();
	fs.open("PhoneDate.bin", std::ios::out | std::ios::in | std::ios::binary);
	if (!fs.is_open())
	{
		cout << "文件打开失败" << endl;
		return false;
	}
	/*   保存增删查的变量*/
	PhoneNumber uTempPhone; //保存用户新增输入时候的客户
	memset((char*)&uTempPhone,0,sizeof(PhoneNumber));
	int nId = { 0 };  //保存用户要删除的Id
	char sUserName[32] = { 0 };//保存用户的输入查找用户名
	memset(sUserName, 0, 32);
	int nIndex = 0;//保存用户的索引
	/*   保存增删查的变量*/


	int selectId = 0;	//保存操作的选择
	int nTem = 0;//保存数值是0 删除数据的时候选择它




	 while(selectId != 7)
	 {
		 system("cls");
		cout << "========" << "欢迎来到电话薄操作" << "========" << endl;
		//封装一个.cpp文件
		cout << "一:显示所有数据。" << endl;
		cout << "二:查询联系人" << endl;
		cout << "三:增加联系人。" << endl;
		cout << "四:修改联系人。" << endl;
		cout << "五:删除联系人。" << endl;
		cout << "六:随机拨打任意联系人。" << endl;
		cout << "七:退出程序。" << endl;
		cout << "请选择操作:" << endl;
	

	
		scanf_s("%d",&selectId);//获取用户的输入
		if (selectId < 7 && selectId > 0)
		{

			switch (selectId)
			{
				case 1://显示出所有的数据
				{
					Phone->SelectAllDate();
					system("pause");
					break;
				}
				case 2://查询单个联系人
				{
					cout << "请输入要查询的用户名:" << endl;
					scanf_s("%s",&sUserName,32);
					nIndex = Phone->SelectOneDateName(sUserName);

					if(nIndex == -1)
					{
						cout << "未找到,请重新选择操作" << endl;
			
					}
					else
					{
						Phone->SelectOneDate(nIndex);

					}

					system("pause");
					break;
				}
				case 3://增加联系人
				{
					//用户输入
					uTempPhone.Id = Phone->GetMaxId();//用户id
					cout << "请输入姓名:" << endl;
					scanf_s("%s",&uTempPhone.m_UserName,32);
					cout << "请输入电话:" << endl;
					scanf_s("%s", &uTempPhone.m_PhoneNunber, 12);
					//写入文件  Phone 要传指针;如果传的是类本身,函数调用完Phone里面的指针将被delete释放
					InsertFileDate(&uTempPhone, Phone);//
					//写入堆空间
					Phone->InsertOneDate(&uTempPhone);
					system("pause");
					break;
				}
				case 4://修改联系人
				{
				

					//先修改文件 :先把要修改的删除操作,在新增一项即可
					cout << "请输入要求改的用户Id" << endl;
					scanf_s("%d",&nId);
					//通过存在内存中的值计算在文件中的偏移
					// 删除
					unsigned FileOffset = Phone->SelectFileOffOneDateId(nId);
					if (FileOffset == 0)
					{
						cout << "输入错误,请重新输入" << endl;
						system("pause");
						break;
					
					}
					// 新增
					uTempPhone.Id = nId;//用户id
					cout << "请输入新的姓名:" << endl;
					scanf_s("%s", &uTempPhone.m_UserName, 32);
					cout << "请输入新的电话:" << endl;
					scanf_s("%s", &uTempPhone.m_PhoneNunber, 12);
					if (InsertFileDate(&uTempPhone, Phone) != 0)
					{
						cout << "修改失败--Insert" << endl;
						break;
					}
					//如果新增成功,就把原来的删除
					if (DeleteFileDate(FileOffset) != 0)
					{
						cout << "修改失败--Delete" << endl;
					}

					//在修改内存; 内存好改  因为是定长方式储存的
					Phone->UpDate(nId, &uTempPhone);


					system("pause");
					break;
				}
				case 5://删除联系人
				{
					//填写用户ID
					cout << "请输入要删除的用户Id号" << endl;
					scanf_s("%d", &nId);
					//获取到用户输入要删除的ID ,在内存中搜索对应的用户
					//需要判断一下  是否找到了
					unsigned FileOffset = Phone->SelectFileOffOneDateId(nId);
					if (!FileOffset == 0)
					{
						//需要判断一下  是否找到了
						//获取到文件偏移 修改文件的数据 把用户Id改为0即可
						if (DeleteFileDate(FileOffset) == 0)
						{
							//内存中删除
							Phone->DeleteDate(nId);
						}
						else
						{
							cout << "文件中修改失败,请重试" << endl;
						}
					}
					system("pause");
					break;
				}
				case 6://拨打任意联系人,且不重复
				{
					Phone->CallAnyName();
					system("pause");
					break;
				}

				case 7://退出
				{
					
					break;//退出循环

				}
			}
		}
	}

	//关闭文件
	 fs.close();
	 // 如果数据有删除或出现Id为0的情况  就把内存中用户的数据重新写入到文件中
 /*
最后一次写入文件,如果这里发生意情况退出程序;那么此时的数据不会保存到文件中
要等close之后才会把数据写入到文件中
*/
	 //文件改名必须先关闭文件  上面已经关闭了
	 if (Phone->GetFlg())
	 {
		 if (rename("PhoneDate.bin", "PhoneDate_Old.bin") == 0) //文件改名.成功就创建新的
		 {
			 fs.open("PhoneDate.bin",ios::out |ios::binary);//创建文件以写的方式
			 if (WriteFileAllDate(Phone) == 0)//证明写入成功了 删除Old文件
			 {
				 remove("PhoneDate_Old.bin");
			 }
		 }
	 }
	
	 getchar();
	return 0;

}





















int WriteFileAllDate(Select* Phone)
{
	//先获取用户数量--内存中获取
	unsigned nNewCount = 0;
	unsigned nCount = Phone->GetnCount();//获取到数量
	pPhoneNumber pTempPhone = Phone->GetSelePhone();//获取到所有用户数据的指针
	fs.seekp(4);//移动文件偏移到第四个字节  前四个是记录用户个数
	for (unsigned i = 0; i < nCount; i++)
	{
		if (pTempPhone->Id != 0)//id不为0就是没有删除的数据  写入到文件中
		{

			unsigned FileOffset = fs.tellp();
			pTempPhone->FileOffset = FileOffset;
			//写用户ID号  
			if (!fs.write((char*)&pTempPhone->Id, 4)) return Write_Error;
			//写用户名字 先获取用户名长度 写入 在写用户名

			char nLen = (char)strlen(pTempPhone->m_UserName);
			if (!fs.write((char*)&nLen, 1)) return -1;
			if (!fs.write((char*)&pTempPhone->m_UserName, nLen)) return Write_Error;

			//写电话号码 先获取电话号码长度 写入 在写电话号码
			nLen = (char)strlen(pTempPhone->m_PhoneNunber);
			if (!fs.write((char*)&nLen, 1)) return -1;
			if (!fs.write((char*)&pTempPhone->m_PhoneNunber, nLen)) return Write_Error;

			//在写文件偏移
			if (!fs.write((char*)&pTempPhone->FileOffset, 4)) return Write_Error;
			nNewCount++;
		}

		pTempPhone++;

	}

	//最后写入个数
	fs.seekp(0);
	if (!fs.write((char*)&nNewCount, 4)) return Write_Error;

	return 0;

}





int InsertFileDate(pPhoneNumber pTempPhone, Select* Phone)
{
	fs.seekp(0, ios_base::end);//设置位置在末尾
				//获取当前文件的偏移
	unsigned FileOffset = fs.tellp();
	pTempPhone->FileOffset = FileOffset;
	//写用户ID号  
	if (!fs.write((char*)&pTempPhone->Id, 4)) return Write_Error;
	//写用户名字 先获取用户名长度 写入 在写用户名

	char nLen = (char)strlen(pTempPhone->m_UserName);
	if (!fs.write((char*)&nLen, 1)) return -1;
	if (!fs.write((char*)&pTempPhone->m_UserName, nLen)) return Write_Error;

	//写电话号码 先获取电话号码长度 写入 在写电话号码
	nLen = (char)strlen(pTempPhone->m_PhoneNunber);
	if (!fs.write((char*)&nLen, 1)) return -1;
	if (!fs.write((char*)&pTempPhone->m_PhoneNunber, nLen)) return Write_Error;

	//在写文件偏移
	if (!fs.write((char*)&pTempPhone->FileOffset, 4)) return Write_Error;

	//文件首地址存的是电话的个数  要加1
	   //先获取文件的个数;
	int nCount = Phone->GetnCount();
	nCount++;
	fs.seekp(0);
	if (!fs.write((char*)&nCount, 4)) return Write_Error;

	fs.flush();//写入到I/O文件,刷新文件;
	return 0;
}


Select* InitReadDate()
{
	/*
	  函数功能:打开文件,把数据读取到堆内存中
	  返回值  int类型  ---用来判断错误  读取文件失败返回-1 正常返回 0
	  参数     无
	*/
	fs.open("PhoneDate.bin", std::ios::in | std::ios::binary);
	if (!fs.is_open())//判断文件是否存在,不存在创建一个新的
	{
		//清除一些标志信息
		fs.clear();
		// 创建文件
		fs.open("PhoneDate.bin", std::ios::out);
		fs.close();
		fs.open("PhoneDate.bin", std::ios::in | std::ios::binary);//以读的方式打开
	}
	cout << "读取数据到堆" << endl;

	//先读四个字节--->获取联系人的个数
	int nCount = 0;
	if (!fs.read((char*)&nCount, 4)) return (Select*)Read_Error;
	Select* Phone = new Select(nCount);
	char nLen = 0;
	//把文件的数据读取到堆中
	pPhoneNumber SelePhone = Phone->GetSelePhone();
	for (int i = 0; i < nCount; i++)
	{
		//读取联系人ID号

		if (!fs.read((char*)(&SelePhone->Id), 4)) return (Select*)Read_Error;
		//cout << std::dec << SelePhone->Id << "   ";
		if (!fs.read(&nLen, 1))return (Select*)Read_Error;//获取字符串的长度
		//读取联系人姓名
		if (!fs.read(SelePhone->m_UserName, nLen)) return (Select*)Read_Error;
		//cout << SelePhone->m_UserName << "    ";
		if (!fs.read(&nLen, 1)) return(Select*)Read_Error;//获取字符串的长度
		//读取联系人的电话号码
		if (!fs.read(SelePhone->m_PhoneNunber, nLen)) return (Select*)Read_Error;
		//cout << SelePhone->m_PhoneNunber << "    ";
		//读取所在文件的偏移位置
		if (!fs.read((char*)&SelePhone->FileOffset, 4)) return (Select*)Read_Error;
		//cout << SelePhone->FileOffset << endl;

		//指针步伐加1
		SelePhone++;
	}
	//下午这里做下处理
	fs.close();
	return Phone;
}

int DeleteFileDate(unsigned FileOffset)
{
	//把数据的Id 在文件中设置为0 代表这个数据被删除了
	int nTem = 0;
	fs.seekp(FileOffset);
	if(!fs.write((char*)&nTem, 4)) return Write_Error;
	fs.flush();

	return 0;
}

Select类–内存中提供增删改查 功能等

Select类源码.h

#pragma once
#include 
#include 
using namespace std;
/*
类用于在内存中管理用户信息
提供增删改查  功能等
*/

/*用户的数据结构体*/
typedef struct uPhoneNumber
{
	int Id;  //用户序列号
	char m_UserName[32];//用户姓名
	char m_PhoneNunber[12];//用户电话号码
	unsigned FileOffset;//在文件的偏移位置   变长的方式存储;如果用定长的化,就记录存入文件的第几个
}PhoneNumber, * pPhoneNumber;

class Select
{
public:
/*
	* Select  //构造函数
	* 参数一:传入用户个数,用来申请堆空间
	* 功能  : 初始化类成员
	* 返回值 无
	*
*/
	Select(unsigned nCount);

/*
	* ~Select  //析构函数
	* 参数一:无
	* 功能  : 释放类成员申请的堆空间
	* 返回值 无
	*
*/
	~Select();
	

/*
	* SelectAllDate
	* 参数一:无
	* 功能  : 把所有用户信息输出到标准设备中(屏幕)
	* 返回值 无
	*
*/
	void SelectAllDate();

/*
	* SelectOneDate  
	* 参数一:类成员指针m_pSelePhone的第几个成员索引
	* 功能  : 查询单个用户信息
	* 返回值 无
	*
*/
	void SelectOneDate(int nIndex);

/*
	* SelectOneDateName
	* 参数一:用户的姓名
	* 功能  : 通过姓名得到用户的类成员指针m_pSelePhone索引
	* 返回值 int类型;成功返回用户的索引 失败返回-1
	*
*/
	unsigned SelectOneDateName(const char* UserName);
/*
	* SelectFileOffOneDateId
	* 参数一:用户ID号
	* 功能  : 返回用户储存文件的偏移
	* 返回值 int类型;成功返回用户的索引 失败返回0
	*
*/
	unsigned SelectFileOffOneDateId(int Id);


/*
	* InsertOneDate
	* 参数一:用户结构体指针 --pPhoneNumber
	* 功能  : 内存中插入一个用户信息
	* 返回值 :无
	*
*/
	void InsertOneDate(pPhoneNumber pTempPhone);

/*
	* UpDate
	* 参数一:用户Id -- UserId
	* 参数二: 用户结构体指针
	* 功能  : 修改内存中用户信息
	* 返回值 :无
	*
*/
	void UpDate(int UserId, pPhoneNumber pTempPhone);

/*
	* DeleteDate
	* 参数一:用户Id -- UserId
	* 功能  : 内存中删除指定用户信息
	* 返回值 :无
	*
*/
	void DeleteDate(int Id);//删除数据
/*
	* CallAnyName   暂未实现
	* 参数一:
	* 功能  : 
	* 返回值 :无
	*
*/
	void CallAnyName();


/*
	* GetMaxId
	* 参数一:无
	* 功能  : 获取用户最大的Id号
	* 返回值 :int  返回用户最大Id号
	*
*/
	int GetMaxId();//获取插入的ID号


/*
	* DrawHead
	* 参数一:无
	* 功能  : 把用户头部信息输出到标准设备中(屏幕)
	* 返回值 :无
*/
	void DrawHead();//封装显示头部
/*
	* IdEmptyFill
	* 参数一:用户ID
	* 功能  : 计算Id后面需要填充空格多少
	* 返回值 :无
*/
	int IdEmptyFill(int Id);

/*
	* GetnCount
	* 参数一:无
	* 功能  : 返回当前用户个数
	* 返回值 :unsigned 
*/
	unsigned GetnCount();//获取用户个数
/*
	* GetSelePhone
	* 参数一:无
	* 功能  : 返回指向用户信息的指针
	* 返回值 :pPhoneNumber指针
*/
	pPhoneNumber GetSelePhone();//获取保存用户指向的堆指针
/*
	* GetStep
	* 参数一:无
	* 功能  : 返回申请堆栈的步长
	* 返回值 :int
*/
	int GetStep();//当内存满了的时候  申请内存的增加步长

/*
	* GetFlg
	* 参数一:无
	* 功能  : 查看是否有修改用户数据,更新等操作
	* 返回值 :bool
*/
	bool GetFlg();//记录是否有修改或删除数据的标志
/*
	* SetSelePhone
	* 参数一:无
	* 功能  : 提供设置类成员接口
	* 返回值 :无
*/
	void SetSelePhone(pPhoneNumber SelePhone);//设置类成员
/*
	* SetCount
	* 参数一:无
	* 功能  : 提供设置类成员接口
	* 返回值 :无
*/
	void SetCount(unsigned nCount);设置类成员
/*
	* BubbleSort
	* 参数一:无
	* 功能  : 冒泡排序法--大循环为次数,内循环为第n和第n+1依次往下对比
	* 返回值 :无
*/
	void BubbleSort();
	//排序--选择排序法 --取最小的索引;先比较数大小 --然后放在第I位
/*
	* SelectionSort
	* 参数一:无
	* 功能  : 选择排序法--大循环为次数,取最小的索引;先比较数大小 --然后放在第I位
	* 返回值 :无
*/
	void SelectionSort();
	
/*
	* InsertSort
	* 参数一:无
	* 功能  : 插入排序法-- --依次往上对比;--   次数一次比一次对比多
	* 返回值 :无
*/
	void InsertSort();
private:
	unsigned m_nCount;//电话的总个数
	int m_nStep = 10;//步长  每次申请堆空间内存的步长
	unsigned m_nSeleLen;//步长+目前的总个数  记录当前m_SelePhone申请的长度
	pPhoneNumber m_pSelePhone;//指向用户数据的指针

	bool m_flg = false;// 记录是否有 id为0的数据

};


Select类源码.cpp

你可能感兴趣的:(c++)