前言
-
用户信息写到文件是变长方式;
-
从文件上读取到内存,也是变长方式
-
用到了三个类;
** 用户信息类 ClassStu
** 自封装字符串类MyStr
** 文件类文章来源:https://www.toymoban.com/news/detail-796353.html -
源码如下
使用如下:文章来源地址https://www.toymoban.com/news/detail-796353.html
cFile MyFile("mydate.bin");
//写入数据
ClassStu* MyStu = new ClassStu(3,"shaguanaodai");
MyFile.WriteFile(MyStu);
//读取--显示文件的数据
//先取个数MyFile--头四个字节放的是个数
int nCount = MyFile.ReadFileHeader();
//申请内存
ClassStu* pStu = new ClassStu[nCount];
memset(pStu, 0, sizeof(ClassStu) * nCount);
MyFile.ReadFileAllDate(pStu, nCount);
delete[] pStu;//释放空间
return 0;
源码
所有类头文件 .h
ClassStu
#pragma once
#include "ClassStr.h"
class ClassStu
{
public:
/*******************构造函数系列开始***********************/
/*
* ClassStu
* 参数一 : int --学生Id
* 参数二 : ClassStr字符串 --学生姓名
* 参数三 : int --文件中的储存偏移
* 功能 :默认构造,初始化类成员 --为空
* 返回值 :无
*/
ClassStu();
/*
* ClassStu
* 参数一 : int --学生Id
* 参数二 : ClassStr字符串 --学生姓名
* 参数三 : int --文件中的储存偏移
* 功能 :默认构造,初始化类成员 --为空
* 返回值 :无
*/
ClassStu(int Id, const char* Name, int FileOffset = 0);
/*
* ClassStu
* 无
* 功能 :析构函数 --释放空间资源
* 返回值 :无
*/
~ClassStu();
/*******************构造函数系列结束***********************/
/*******************获取类成员***********************/
//类成员信息公开
public:
int m_Id; //ID
MyStr* m_StuName;//用户名称
int m_FileOffset;//存在文件的偏移
};
MyStr
#pragma once
#include <iostream>
using namespace std;
/*
*/
class MyStr
{
public:
/*******************构造函数系列开始***********************/
/*
* ClassStr
* 参数一 : 无
* 功能 :默认构造,初始化类成员 --为空
* 返回值 :无
*/
MyStr();
/*
* ClassStr(const char* Str)
* 参数一 : 字符串指针
* 功能 :带参构造,初始化类成员--初始化字符串
* 返回值 :无
*/
MyStr(const char* Str);
/*
* ClassStr(int nNumber)
* 参数一 : 整形
* 功能 :带参构造,初始化类成员--初始化字符串
* 返回值 :无
*/
MyStr(int nNumber);
/*
* ClassStr(char nLen)
* 参数一 :char
* 功能 :初始化一块指定大小的内存;
* 返回值 :无
*/
MyStr(char nLen);
/*
* ClassStr(ClassStr& cStr)
* 参数一 : 类引用
* 功能 :浅拷贝,当类相等的时候调用
* 返回值 :无
*/
MyStr(MyStr& cStr);//字符串设置为浅拷贝,字符串指向同一块内存,增加一个引用计数
/*
* ~ClassStr
* 参数一 : 无
* 功能 :析构函数,释放类成员堆栈资源
* 返回值 :无
*/
~MyStr();
/*******************构造函数系列结束***********************/
/*******************运算符重载系列开始***********************/
/*
* operator=
* 参数一 :类引用
* 功能 :=号运算符重载
* 返回值 :无
*/
void operator= (MyStr& cStr);// =号运算符重载
/*
* operator=
* 参数一 :类引用
* 功能 :=号运算符重载
* 返回值 :无
*/
void operator= (const char* cStr);// =号运算符重载
/*
* operator=
* 参数一 : 整形
* 功能 :=号运算符重载
* 返回值 :无
*/
void operator= (int nNumber);// =号运算符重载
/*
* operator+
* 参数一 : 整形
* 功能 :+号运算符重载
* 返回值 :无
*/
int operator+ (int nNumber);// =号运算符重载
/*
* operator-
* 参数一 : 整形
* 功能 :+号运算符重载
* 返回值 :无
*/
int operator- (int nNumber);// =号运算符重载
/*
* operator[]
* 参数一 : 整形
* 功能 :修改字符串索引值
* 返回值 :无
* 实现类可以直接[]修改值
* ClassStr cStr = "wooaoaoa0ao";
* cStr[3] = 'b';
*/
char& operator[] (int nIndex);// =号运算符重载
/*******************运算符重载系列结束***********************/
/*******************获取类成员系列开始***********************/
/*
* GetStr
* 参数一 : 无
* 功能 :返回m_str字符串
* 返回值 :char*
*/
char* GetStr();
/*
* GetLen
* 参数一 : 无
* 功能 :返回m_str字符串
* 返回值 :char*
*/
int GetLen();
/*******************获取类成员系列结束***********************/
/* 增删改查系列查这里开始*/
/*******************字符串增加功能开始***********************/
/*
* Insert
* 参数一 : int 插入位置
* 参数二 :const char* 插入字符串
* 功能 :往字符串里面插入字符
* 返回值 :char*
*/
MyStr& Insert(int nPosition,const char* str);
/*
* FrontInsert
* 参数一 : 无
* 功能 :往字符串头部插入字符
* 返回值 :void
*/
void FrontInsert(const char* str);
/*
* TailInsert
* 参数一 : 无
* 功能 :往字符串尾部插入字符
* 返回值 :void
*/
void TailInsert(const char* str);
/*******************字符串插入功能结束***********************/
/*******************字符串删除功能开始***********************/
/*
* Delete
* 参数一 : int 索引
* 参数二 : int 删除数量
* 功能 :往字符串尾部插入字符
* 返回值 :ClassStr&
*/
MyStr& Delete(int nIndex,int nCount);
/*******************字符串删除功能结束***********************/
/*******************字符串查找功能开始***********************/
/*
* HeadFind
* 参数一 : const char* str
* 功能 :首部开始查找字符串
* 返回值 :返回索引,失败返回-1;
*/
int HeadFind(const char* str);
/*
* TailFind
* 参数一 : const char* str
* 功能 :尾部开始查找字符串
* 返回值 :返回索引,失败返回-1;
*/
int TailFind(const char* str);
/*
* HeadFindCount
* 参数一 : const char* str
* 功能 :首部开始查找字符串,返回该字符串出现过的次数
* 返回值 :int 返回次数;一次未出现过返回0
直接调用了IsCmpContinuesHead函数来判断是否为-1 ,效率上会低点,可以优化;
*/
int HeadFindCount(const char* str);
/*******************字符串查找功能结束***********************/
/*******************字符串修改功能开始***********************/
/*
* Modify
* 参数一 : const char* str nStr:字符串中需要被修改的字符
* 参数二 : const char* str :改变成这个字符串
* 参数三 : bool :是所有替换,还是只替换一次 false一次 true 所有替换
* 功能 :字符串修改替换
* 返回值 :int 成功返回修改次数 如果一次都没替换返回-2
*/
int Modify(const char* nStr,const char* cStr,bool bmp = false);
/*******************字符串修改功能结束***********************/
/*******************字符串删除功能开始***********************/
//删除功能如果做的话 需要重新重构类成员,要填写 start 和end 来记录字符串的起始和结束位置;
//我只做这个小型字符串 平时的修改的小功能
/*******************字符串删除功能结束***********************/
/* 增删改查系列查这里结束*/
/*******************内部小功能函数系列开始***********************/
private://类内部调用函数
/*
* NumberCount
* 参数一 : int --整数
* 功能 :得到这个整数有多少个
* 返回值 :整数的个数
*/
int NumberCount(int nNumber);
/*
* GetDivNum
* 参数一 : int --整数的个数
* 功能 :求出一个10 100 1000 10000
* 返回值 :int
*/
int GetDivNum(int NumberCount);
/*
* IsStr
* 参数一 :无
* 功能 :检测初始化m_Str是否为空;如果NEW申请失败就会返回nullptr
* 返回值 :bool
*/
bool IsStr();
/*
* IsPnCount()
* 参数一 :无
* 功能 :检测初始化m_p_nCount是否为空;如果NEW申请失败就会返回nullptr
* 返回值 :bool
*/
bool IsPnCount();
/*
* FreeSpace()
* 参数一 :无
* 功能 :检测初始化m_p_nCount是否为空;如果NEW申请失败就会返回nullptr
* 返回值 :bool
*/
void FreeSpace();
/*
* InitNumber()
* 参数一 :无
* 功能 :用户构造整数初始化和=号整数重载运算
* 返回值 :bool
*/
void InitNumber(int nNumber);
/*
* InitSpace()
* 参数一 :无
* 功能 :初始化一块指定大小的内存空间
* 返回值 :bool
*/
void InitSpace(char nLen);
/*
* StrToNumber
* 参数一 :无
* 功能 :把类成员m_Str字符串转化为数字返回;
* 返回值 :int
*/
int StrToNumber();
/*
* FrontInsert
* 参数一 :源地址;缓存地址
* 参数二 :缓存大小
* 参数三 : 目标地址;拷贝的地址
* 参数四 :需要拷贝多少个字节
* 功能 :前排插入
* 返回值 :void
*/
void FrontInsert(char* NewStr, int nSumLen, const char* str, int nLen);
/*
* TailInsert
* 参数一 :源地址;缓存地址
* 参数二 :缓存大小
* 参数三 : 目标地址;拷贝的地址
* 参数四 :需要拷贝多少个字节
* 功能 :尾部插入
* 返回值 :void
*/
void TailInsert(char* NewStr, int nSumLen, const char* str, int nLen);
/*
* MiddleInsert
* 参数一 :源地址;缓存地址
* 参数二 :缓存大小
* 参数三 : 目标地址;拷贝的地址
* 参数四 :需要拷贝多少个字节
* 参数五 :插入的位置
* 功能 :中间插入一个字符串
* 返回值 :void
*/
void MiddleInsert(char* NewStr, int nSumLen, const char* str, int nLen,int nPosition);
/*
* IsCmpByte(char chByte)
* 参数一 :char 字节
* 功能 :查字符串里面是否包含这个字节
* 返回值 :int ---返回查找到的字符串位置索引
*/
int IsCmpByteHead(char chByte,int nIndex);
/*
* IsCmpByte(char chByte)
* 参数一 :char 字节
* 功能 :查字符里面是否出现过这个字节
* 返回值 :int ---返回查找到的字符串位置索引
*/
int IsCmpByteTail(char chByte, int nIndex);
/*
*
* IsCmpByteContinues(const char* str, int nLen,int nIndex)
* 参数一 :const char* str 需要对比的字符串
* 参数二 :int str长度
* 参数三 :int nIndex m_Str索引
* 参数四 :int nIn str的索引
* 功能 :给定目标和源目标索引,连续对比每一个字节是否匹配
* 返回值 :int ---返回查找到的字符串位置索引
*/
bool IsCmpByteContinues(const char* str, int nLen, int nIndex, int nIn);
/*
*
* IsCmpContinuesHead(char chByte) 正向查找
* 参数一 :const char* str
* 参数二 :int nLen字符串长度
* 参数三 :int nIndex m_Str索引
* 功能 :查字符里面是否出现过这个字节
* 返回值 :int ---返回查找到的字符串位置索引
*/
int IsCmpContinuesHead(const char* str, int nLen, int nIndex);
/*
* IsCmpContinuesTail(char chByte) 反向查找
* 参数一 :const char* str
* 参数二 :int nLen字符串长度
* 参数三 :int nIndex m_Str索引
* 参数四 :TailIndex 判断对比到时候退出
* 功能 :查字符里面是否出现过这个字节
* 返回值 :int ---返回查找到的字符串位置索引
*/
int IsCmpContinuesTail(const char* str, int nLen, int nIndex);
/*
*Replace(const char* cStr,int nIndex)
* 参数一 :const char* str 替换的字符串
* 参数二 :nIndex this字符串的索引
* 功能 :替换字符串
* 返回值 :无
*/
void Replace(const char* cStr,int nIndex);
/*******************内部小功能函数系列结束***********************/
private://类成员以m_开头定义
int m_nCount;//记录字符串的个数
char* m_Str;//字符串指针
int* m_p_nCount;//记录有多少个指针指向它;
};
cFile
#pragma once
#include <iostream>
#include "ClassStr.h"
#include "ClassStu.h"
using namespace std;
/*
*
* 明天测试一下文件类 -- 完成
* 删除和改名文件-- 完成
* 字符串类加入进来测试 --
*
* 有想一起学习c++的,,一起努力坚持下去:加入(q) :553235560
*/
class cFile
{
public:
enum FileType { WRITEERR = -3, READERR, PNULL , SUCCESS = 1 };
public:
/*******************默认构造系列开始*************************/
/*
* cFile
* 参数一 : 无
* 功能 :默认构造,初始化类成员 --为空
* 返回值 :无
*/
cFile();
/*
* cFile(const char* FileName,const char* Mode)
* 参数一 : const char* FileName --文件的目录地址
* 功能 :默认构造打开文件,初始化类成员
* 返回值 :无
*/
cFile(const char* FileName);
/*
* cFile(cFile& fFile)
* 参数一 : 无
* 功能 :默认构造,初始化类成员 --为空
* 返回值 :无
*/
cFile(const cFile& fFile);
/*
* ~cFile()
* 参数 :无
* 功能 :释放类资源
* 返回值 :无
*/
~cFile();
/*******************默认构造系列结束*************************/
/*******************文件读系列开始*************************/
/*
* ReadFileHeader(int* nCount)
* 参数一 :无
* 功能 :获取文件首四个字节 为用户个数
* 返回值 :成功返回个数,失败返回-1
*/
int ReadFileHeader();
/*
* ReadFile(void* buffer,int FileOffset = 0)
* 参数一 :void* buffer 读出数据放入的缓冲区
* 功能 :从文件中读取数据放入缓冲区中
* 返回值 :FileType
*/
FileType ReadFileAllDate(ClassStu* pStudent,int nCount);
/*******************文件读系列结束*************************/
/*******************文件写系列开始*************************/
/*
* WriteFile()
* 参数一 :const void* buffer 要写入的字符串
* 功能 :检查m_pFile是否为nullptr. 文件是否打开成功
* 返回值 :FileType
*/
int WriteFile(ClassStu* pStudent,int FileOffset = 0);
/*******************文件写系列结束*************************/
/*
* UpDateHeader(bool bTmp);
* 参数一 :bool ;默认是true 代表头部四个字节加1 flase 代表头部减1
* 功能 : 用户个数的加减操作
* 返回值 :FileType
*/
FileType UpDateHeader(bool bTmp = true);
/*******************内部调用函数系列*************************/
/*
* ReFileName(const char* old_filename, const char* new_filename)
* 参数一 :const char* old_filename 要修改的文件路径和名字
* 参数一 :const char* new_filename 文件的新名
* 功能 :修改文件名
* 返回值 :int 成功返回0 错误非0值
*/
int ReFileName(const char* old_filename, const char* new_filename);
/*
* DeleteFile(const char* FileName)
* 参数一 :const char* FileName 当前文件下的文件名
* 功能 :删除文件
* 返回值 :int类型 成功返回0 错误非0值
*/
int DeleteFile(const char* FileName);
private:
/*
* CloseFile()
* 参数 :无
* 功能 :关闭文件
* 返回值 :无
*/
void CloseFile();
/*
* ~IsOpen()
* 参数 :无
* 功能 :检查m_pFile是否为nullptr. 文件是否打开成功
* 返回值 :bool
*/
bool IsOpen();
/*
* WriteFileDate(void* buffer,int nSize)
* 参数一 :void* buffer 要写入文件的字符串缓冲区
* 参数二 : int nSize 要写入多少个字节
* 功能 :封装文件fwrite函数;使用起来更加方便
* 返回值 :FileType
*/
FileType WriteFileDate(void* buffer, int nSize);
/*
* ReadFileDate(void* buffer,int nSize)
* 参数一 :void* buffer 读出数据放入的缓冲区
* 参数二 : int nSize 要从文件中读多少个字节
* 功能 :封装文件fread函数;使用起来更加方便
* 返回值 :FileType
*/
FileType ReadFileDate(void* buffer, int nSize);
private:
FILE* m_pFile;//文件指针
int* m_nCount;//引用技术,记录被赋值次数
};
所有文件的实现源码.cpp
classstu
#include "ClassStu.h"
ClassStu::ClassStu()
{
m_StuName = nullptr;
m_Id = 0;
m_FileOffset = 0;
}
ClassStu::ClassStu(int Id, const char* Name, int FileOffset)
{
if (Name == nullptr)
{
return;
}
m_StuName = new MyStr(Name);
m_Id = Id;
m_FileOffset = FileOffset;
}
ClassStu::~ClassStu()
{
if (m_StuName != nullptr)
{
delete m_StuName;//释放字符串空间
}
}
Mystr
#include "ClassStr.h"
MyStr::MyStr()
{
m_nCount = 0;
m_Str = nullptr;
m_p_nCount = new int(0);
}
MyStr::MyStr(const char* Str)
{
//先求传入字符串的长度 strlen长度为字符串,不包含/0;
if (Str == nullptr)
{
return;
}
int nLen = strlen(Str);
//在申请空间
m_nCount = nLen + 1;
m_Str = new char[m_nCount];
m_p_nCount = new int(0);
if (!IsStr())
{
cout << "str内存初始化失败" << endl;
}
else
{
//申请的地址初始化为0
memset(m_Str, 0, m_nCount);
//在传入的地址进行拷贝操作
memcpy_s(m_Str, nLen, Str, nLen);
}
}
MyStr::MyStr(int nNumber)
{
FreeSpace();
//先求出整形有几位 NumberCount返回整形有几位数字;
InitNumber(nNumber);
}
MyStr::MyStr(char chNumber)
{
InitSpace(chNumber);
}
MyStr::MyStr(MyStr& cStr)
{
m_nCount = cStr.m_nCount;
m_Str = cStr.m_Str;
m_p_nCount = cStr.m_p_nCount;
if (m_p_nCount != nullptr)
{
(*m_p_nCount)++;
}
}
void MyStr::operator=(MyStr& cStr)
{
//先清除自身
FreeSpace();
m_Str = cStr.m_Str;
m_nCount = cStr.m_nCount;
m_p_nCount = cStr.m_p_nCount;
(*m_p_nCount)++;
}
void MyStr::operator=(const char* cStr)
{
if (cStr == nullptr)
{
return;
}
int nLen = strlen(cStr);
//在申请空间
m_nCount = nLen + 1;
m_Str = new char[m_nCount];
if (m_Str == nullptr)
{
cout<<"初始化字符串失败"<<endl;
return;
}
m_p_nCount = new int(0);
//申请的地址初始化为0
memset(m_Str, 0, m_nCount);
//在传入的地址进行拷贝操作
memcpy_s(m_Str, nLen, cStr, nLen);
}
void MyStr::operator=(int nLen)
{
//等号的时候做出初始化
if (nLen <= 0)
{
cout << "nNumber初始化字符串长度不能为0" << endl;
return;
}
m_nCount = nLen + 1;
m_p_nCount = new int(0);
m_Str = new char[m_nCount];
if (!IsStr())
{
cout << "m_Str:申请内存空间失败" << endl;
return;
}
}
int MyStr::operator+(int nNumber)
{
//先把字符串转化为数字
int nTmp = StrToNumber();
nTmp = nTmp + nNumber;
return nTmp;
}
int MyStr::operator-(int nNumber)
{
int nTmp = StrToNumber();
nTmp = nTmp - nNumber;
return nTmp;
}
char& MyStr::operator[](int nIndex)
{
char* ch = nullptr;
if (nIndex < 0 || nIndex> m_nCount)
{
return *ch;
}
return m_Str[nIndex];
}
MyStr::~MyStr()
{
//判断引用计数是否为0
if (*m_p_nCount != 0)
{
(*m_p_nCount)--;
}
else //释放内存空间
{
delete[] m_Str;
delete m_p_nCount;
}
}
char* MyStr::GetStr()
{
return m_Str;
}
int MyStr::GetLen()
{
return m_nCount -1;
}
MyStr& MyStr::Insert(int nPosition, const char* str)
{
if (0 > nPosition || nPosition > m_nCount || str == NULL)
{
cout << "插入错误:请选择正确的位置或str指针为NULL" << endl;
return *this;
}
int nLen = strlen(str);//字符串的长度
int nSumLen = nLen + m_nCount;
char* NewStr = new char[nSumLen];//字符串申请总长度
if (NewStr == nullptr)
{
cout << "内存申请失败" << endl;
return *this;
}
memset(NewStr,0,nSumLen);//申请的内存设置为0
//可以分为插入头部 尾部 还有是中部
if (nPosition == 0)//头部处理
{
FrontInsert(NewStr, nSumLen, str, nLen);
}
else if (nPosition == m_nCount)//尾部处理
{
TailInsert(NewStr, nSumLen, str, nLen);
}
else//中部
{
MiddleInsert(NewStr, nSumLen, str, nLen, nPosition);
}
//释放自身字符串空间
delete[] m_Str;
m_Str = NewStr;
m_nCount = nSumLen;
return *this;
}
void MyStr::FrontInsert(const char* str)
{
Insert(0, str);
}
void MyStr::TailInsert(const char* str)
{
Insert(m_nCount, str);
}
MyStr& MyStr::Delete(int nPosition, int nCount)
{
//删除头部 中间 尾部
int nLen = m_nCount - nPosition - 1;
if (nLen = nCount)
{
m_Str[nPosition] = '\0';
}
return*this;
}
int MyStr::HeadFind(const char* str)
{
if (str == NULL)return -1;
int nLen = strlen(str);
int nIndex = 0;//字符串开始查找的位置
int nCount = 0;
//一 :这是判断的是一个字符对比的情况
if (nLen == 1)
{
return IsCmpByteHead(str[0], nIndex);//IsCmpByteHead 一个字符 在m_Str字符串中循环判断一次
}
//二:长度和字符串长度一样,就匹配每一个字节是否相等
if (nLen == (m_nCount -1))
{
if (IsCmpByteContinues(str, nLen, 0,0))//IsCmpByteHead 一个字符 在m_Str字符串中循环判断一次
{
return 0;
}
}
//三:这判断是多个字符的对比情况
return IsCmpContinuesHead(str, nLen, nIndex);
}
int MyStr::TailFind(const char* str)
{
if (str == NULL)return false;
int nLen = strlen(str);
int nIndex = m_nCount - nLen -1;//字符串开始查找的位置
int nCount = 0;
if (nLen == 1)
{
return IsCmpByteTail(str[0], nIndex);
}
//二:长度和字符串长度一样,就匹配每一个字节是否相等
if (nLen == (m_nCount - 1))
{
if (IsCmpByteContinues(str, nLen, 0,0))//IsCmpByteHead 一个字符 在m_Str字符串中循环判断一次
{
return 0;
}
}
return IsCmpContinuesTail(str, nLen, nIndex);
}
int MyStr::HeadFindCount(const char* str)
{
if (str == nullptr)return -1;
int nCount = 0;
int nLen = strlen(str);
int nIndex = 0;
do{
nIndex = IsCmpContinuesHead(str, nLen, nIndex);
if (nIndex == -1)
{
return nCount;
}
nCount++;
//找到了索引值就要增加nLen之后的位置开始查找
nIndex = nIndex + nLen;
} while (true);
return nCount;
}
int MyStr::Modify(const char* nStr, const char* cStr, bool bmp)
{
//记录替换的次数
int nCount = 0;
int nLen = strlen(cStr);
int nIndex = 0;
do
{
nIndex = IsCmpContinuesHead(nStr, nLen, nIndex);
if (nIndex == -1)
{
return nCount;
}
nCount++;
// 在替换 --需要替换的字符串 和this字符串索引
Replace(cStr,nIndex);
//找到了索引值就要增加nLen之后的位置开始查找
nIndex = nIndex + nLen;
} while (bmp);
return nCount;
}
int MyStr::NumberCount(int nNumber)
{
//求数字有多少位
int nLen = 0;
while (nNumber != 0)
{
nNumber = nNumber / 10;
nLen++;
}
return nLen;
}
int MyStr::GetDivNum(int nLen)
{
int DivNum = 1;
while ( nLen > 1 )
{
DivNum = DivNum * 10;
nLen--;
}
return DivNum;
}
bool MyStr::IsStr()
{
if (m_Str == nullptr)
{
return false;
}
return true;
}
bool MyStr::IsPnCount()
{
if (m_p_nCount == nullptr)
{
return false;
}
return true;
}
void MyStr::InitNumber(int nNumber)
{
m_p_nCount = new int(0);
int nLen = NumberCount(nNumber);
m_nCount = nLen + 1;
m_Str = new char[m_nCount];
if (!IsStr())
{
cout << "内存初始化失败" << endl;
}
else
{
memset(m_Str, 0, m_nCount);
int nDivNum = GetDivNum(nLen);
int nIndex = 0;
//在把每一位数字转换为字符串 数字的1 和字符串的1 先除,在取模
for (int i = 0; i < m_nCount - 1; i++)
{
m_Str[nIndex] = (char)(nNumber / (1 * nDivNum)) + '0';
nIndex++;
nNumber = nNumber % (1 * nDivNum);
nDivNum = nDivNum / 10;
}
}
}
void MyStr::InitSpace(char nLen)
{
if (nLen <= 0)
{
cout << "nNumber初始化字符串长度不能为0" << endl;
return;
}
m_nCount = nLen + 1;
m_p_nCount = new int(0);
m_Str = new char[m_nCount];//申请堆内存
if (!IsStr())
{
cout << "m_Str:申请内存空间失败" << endl;
return;
}
memset(m_Str,0, m_nCount);//全部初始化为0
}
int MyStr::StrToNumber()
{
int nTmp = 0;
int nImu = GetDivNum(m_nCount - 1);
for (int i = 0; i < m_nCount - 1; i++)
{
char chCtr = m_Str[i];
int nNum = (int)chCtr - '0';
nTmp += nNum * nImu;
nImu = nImu / 10; //nImu = 10
}
return nTmp;
}
void MyStr::FrontInsert(char* NewStr, int nSumLen, const char* str,int nLen)
{
//种方式也可以
//memcpy_s(NewStr, nSumLen, str, nLen);
//memcpy_s(NewStr + nLen, nSumLen, m_Str, m_nCount - 1);
//另种方式也可以
MiddleInsert(NewStr, nSumLen, str, nLen,0);
}
void MyStr::TailInsert(char* NewStr, int nSumLen, const char* str, int nLen)
{
//memcpy_s(NewStr, nSumLen, m_Str, m_nCount - 1);
//memcpy_s(NewStr + m_nCount - 1, nSumLen, str, nLen);
MiddleInsert(NewStr, nSumLen, str, nLen, m_nCount -1);
}
void MyStr::MiddleInsert(char* NewStr, int nSumLen, const char* str, int nLen, int nPosition)
{
memcpy_s(NewStr, nSumLen, m_Str, nPosition);//5wo ai6
memcpy_s(NewStr + nPosition, nSumLen, str, nLen);
memcpy_s(NewStr + nLen + nPosition, nSumLen, m_Str + nPosition, m_nCount - nPosition -1);
}
int MyStr::IsCmpByteHead(const char chByte,int nIndex)
{
for (int i = nIndex; i < m_nCount -1; i++)
{
if (m_Str[i] == chByte)
{
return i;
}
}
return -1;
}
int MyStr::IsCmpByteTail(const char chByte, int nIndex)
{
for (int i = nIndex; i >= 0; i--)
{
if (m_Str[i] == chByte)
{
return i;
}
}
return -1;
}
bool MyStr::IsCmpByteContinues(const char* str, int nLen, int nIndex,int nIn)
{
for (int i = nIn; i < nLen; i++)
{
if (m_Str[nIndex] != str[i])
{
return false;
}
nIndex++;
}
return true;
}
int MyStr::IsCmpContinuesHead(const char* str,int nLen,int nIndex)
{
int nLenCmp = 0;
int nIn = 1;
//正向查找
do {
//先查找第一个字节 ---在字符串中有没有,有返回索引
nIndex = IsCmpByteHead(str[0], nIndex);
//如果尾部查找到str[0],剩余的字节不够对比直接返回-1
//str "ghy" m_str "erergh" 找到了g,但是m_str后面只有2个字符;肯定返回-1
nLenCmp = m_nCount - 1 - nIndex;
if (nIndex == -1 || nLenCmp < nLen)
{
return -1;
}
//如果第一个字节存在,连续对比m_str和str的每一个字节
if (IsCmpByteContinues(str, nLen, nIndex + nIn, nIn))
{
return nIndex;
}
nIndex++ ;//正向查找
} while (true);
return -1;
}
int MyStr::IsCmpContinuesTail(const char* str, int nLen, int nIndex)
{
int nLenCmp = 0;
int nIn = 1;
do {
//先查找第一个字节 ---在字符串中有没有,有返回索引
nIndex = IsCmpByteTail(str[0], nIndex);//反向查找
nLenCmp = m_nCount - 1 - nIndex;
if (nIndex == -1 || nLenCmp < nLen)
{
return -1;
}
//如果第一个字节存在,连续对比m_str和str的每一个字节
if (IsCmpByteContinues(str, nLen, nIndex + nIn, nIn))
{
return nIndex;
}
nIndex--;//反向查找
} while (true);
return -1;
}
void MyStr::Replace(const char* cStr, int nIndex)
{
int nLen = strlen(cStr);
for (int i = 0; i < nLen; i++)
{
m_Str[nIndex] = cStr[i];
nIndex++;
}
}
void MyStr::FreeSpace()
{
if (!IsStr())
{
return;
}
delete[] m_Str;
delete m_p_nCount;
}
cFile
#include "cFile.h"
cFile::cFile(const cFile& fFile)
{
m_pFile = nullptr;
m_nCount = NULL;
if (fFile.m_pFile != nullptr)
{
m_pFile = fFile.m_pFile;
m_nCount = fFile.m_nCount;
(*m_nCount)++;
}
}
cFile::cFile()
{
m_pFile = nullptr;
m_nCount = nullptr;
}
cFile::cFile(const char* FileName)
{
//以读写方式打开文件
fopen_s(&m_pFile, FileName, "r+b");//从文件头开始读,可读可写
m_nCount = new int(0);
if (!IsOpen())//文件打开不成功
{
//文件打开不成功,就创建一个新文件 从文件尾开始写
fopen_s(&m_pFile, FileName, "w+b");
//写入四个字节 ---也可以检测文件是否打开成功
if (WriteFileDate(m_nCount, 4) != SUCCESS)
{
cout << "初始化失败" << endl;
}
fflush(m_pFile);
}
}
cFile::~cFile()
{
if (*m_nCount != 0)
{
(*m_nCount)--;
}
else
{
CloseFile();//关闭文件
delete m_nCount;
}
}
bool cFile::IsOpen()
{
if (m_pFile == nullptr)
{
return false;
}
return true;
}
int cFile::ReadFileHeader()
{
//文件偏移移动到首
rewind(m_pFile);
int nCount = 0;
//从文件读四个字节到nCount /成功返回读取了多少个字节
if (fread((char*)&nCount, 1, 4, m_pFile) == 4)
{
return nCount;
}
return 0;
}
cFile::FileType cFile::ReadFileAllDate(ClassStu* pStudent,int nCount)
{
//1:检测缓冲区地址是否为空
if (pStudent == nullptr)
{
return PNULL;
}
//2:循环读取文件中用户信息--》缓存中
char nLen = {0};
for (int i = 0; i < nCount; i++)
{
//2.1 先读用户的ID
if (ReadFileDate(&pStudent->m_Id, 4) == READERR)
{
return READERR;
}
//2.2 在读字符串的字节数
if (ReadFileDate(&nLen, 1) == READERR)
{
return READERR;
}
//2.3 在读字符串
pStudent->m_StuName = new MyStr(nLen);
if (ReadFileDate(pStudent->m_StuName->GetStr(), nLen) == READERR)
{
return READERR;
}
//2.4 在读文件偏移
if (ReadFileDate(&pStudent->m_FileOffset, 4) == READERR)
{
return READERR;
}
pStudent++;//步长++
}
return SUCCESS;
}
cFile::FileType cFile::ReadFileDate(void* buffer, int nSize)
{
if (buffer == nullptr || nSize <= 0)
{
return READERR;
}
if (fread(buffer, 1, nSize, m_pFile) == nSize)
{
return SUCCESS;
}
return READERR;
}
int cFile::WriteFile(ClassStu* buffer,int FileOffset)
{
//1:判断传入的指针是否为空
if(buffer == nullptr)
{
return WRITEERR;
}
//2:将文件偏移指向要写入的位置
if (FileOffset == 0)
{
fseek(m_pFile, FileOffset, SEEK_END);//移动到尾部开始写入
}
else
{
fseek(m_pFile, FileOffset, SEEK_SET);//移动到指定位置写入;
}
ClassStu* pStudent = buffer;
//3.0 获取文件偏移,后面可以写入
FileOffset = ftell(m_pFile);
if (FileOffset == -1L)
{
return WRITEERR;
}
//3.1 先写入学生Id
if (WriteFileDate(&pStudent->m_Id, sizeof(int)) != SUCCESS)
{
return WRITEERR;
}
//3.2 再写入用户名称的字符串长度
int nLen = pStudent->m_StuName->GetLen();
if (WriteFileDate(&nLen, sizeof(char)) != SUCCESS)
{
return WRITEERR;
}
//3.3 写入用户的姓名
if (WriteFileDate(pStudent->m_StuName->GetStr(), pStudent->m_StuName->GetLen()) != SUCCESS)
{
return WRITEERR;
}
//3.4 写入文件偏移
if (WriteFileDate(&FileOffset, sizeof(int)) != SUCCESS)
{
return WRITEERR;
}
//3.5 修改首部四个字节用户个数
UpDateHeader();
if (fflush(m_pFile) == 0)
{
cout << "写入文件成功了" << endl;
}
return SUCCESS;
}
cFile::FileType cFile::WriteFileDate(void* buffer, int nSize)
{
if (buffer == nullptr || nSize <= 0)
{
return WRITEERR;
}
if (fwrite(buffer, 1, nSize, m_pFile) == nSize)
{
return SUCCESS;
}
return WRITEERR;
}
void cFile::CloseFile()
{
fclose(m_pFile);
}
int cFile::ReFileName(const char* old_filename, const char* new_filename)
{
return rename(old_filename, new_filename);
}
int cFile::DeleteFile(const char* FileName)
{
return remove(FileName);
}
cFile::FileType cFile::UpDateHeader(bool bTmp)
{
//先读
int nCount = ReadFileHeader();
if (nCount == -1)
{
return READERR;
}
bTmp ? nCount++ : nCount--;
fseek(m_pFile,0,SEEK_SET);//移动到头部
//再写
if (WriteFileDate(&nCount, 4) != SUCCESS)
{
return WRITEERR;
}
fflush(m_pFile);
return SUCCESS;
}
到了这里,关于c++简单做一个文件变长储存(自己封装字符串类)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!