用来自我加强练习
之后增加–优化封装一个文件类
自我记录一下
#include <iostream>
#include <fstream>
//#include <cstdio> //
#include "Select.h"
#include <conio.h>
//#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;
}
#pragma once
#include <iostream>
#include <iomanip>
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的数据
};