c++简单做一个文件变长储存(自己封装字符串类)

这篇具有很好参考价值的文章主要介绍了c++简单做一个文件变长储存(自己封装字符串类)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

  • 用户信息写到文件是变长方式;

  • 从文件上读取到内存,也是变长方式

  • 用到了三个类;
    ** 用户信息类 ClassStu
    ** 自封装字符串类MyStr
    ** 文件类

  • 源码如下
    使用如下:文章来源地址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模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • PHP最简单自定义自己的框架数据库封装调用(五)

    1、实现效果调用实现数据增删改查封装   2、创建数据表    3、index.php 入口定义数据库账号密码 4、KJ.php引入基类 5、基类使用pdo封装增删改查 ModelBase.php 6、indexCrl.php控制器调用 7、完整KJ.php代码

    2024年02月13日
    浏览(40)
  • C++ puts()函数(输出简单字符串)

    C++中的 puts() 函数是用来输出字符串的函数,它的原型如下: 其中, str 是要输出的字符串, puts() 函数会自动在字符串末尾添加一个换行符 n ,并将其输出到标准输出流(即屏幕)上。 相比于 cout 输出流, puts() 函数的优点是简单易用,不需要像 cout 一样需要使用 运算符来

    2024年02月05日
    浏览(48)
  • C++字符串题基础(进阶请看下一个文章)

    打印小写字母表 时间的差 数字和 国王的魔镜 简单解密 查字典码中最小的字符串 出现最多的小写字母 判断是否构成回文 移动个空格 删除* 字符串反码 看完动漫要几天?不会 时钟旋转不会 字符串加密

    2024年02月15日
    浏览(37)
  • 自己动手搭网站(六):javaweb搭建一个简单的个人博客系统

    这篇博主会介绍下我用javaweb搭建的个人博客系统,源码也会打包放到gitee上,需要的朋友可以自取,大家互相学习,请不要直接CV。 tip:本篇承上篇,许多基本内容在上篇谈到,建议看之前先浏览下上篇博客。 上篇:自己动手搭网站(五):javaweb基础:登录功能 系列总目录

    2024年02月07日
    浏览(48)
  • 【C++ OJ练习】5.字符串最后一个单词的长度

    字符串最后一个单词的长度_牛客题霸_牛客网 倒着找第一个空格的下标 用下标之间的差来计算  【C++ OJ练习】5.字符串最后一个单词的长度 完

    2024年02月13日
    浏览(56)
  • C++函数isStringNumeric,用于检查一个字符串是否只包含数字字符。

    C++函数isStringNumeric,用于检查一个字符串是否只包含数字字符。 函数接受一个 std::string 类型的参数 str ,表示要检查的字符串。 函数使用了一个循环遍历字符串中的每个字符,对于每个字符,通过 std::isdigit(ch) 函数判断它是否是数字字符。如果存在非数字字符,则返回 fal

    2024年02月09日
    浏览(62)
  • 【Linux】封装一下简单库 && 理解文件系统

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、封装一下简单库 二、理解一下stdin(0)、stdout(1)、stderr(3) 2.1、为什么要有0、1、2呢? 2.2、特点 2.3、如果我想让2也和1重定向到一个文件中? 三、理解文件系统 3.1、看看物理磁盘 3.2、了解

    2024年04月22日
    浏览(40)
  • 创建你自己的ERC-721代币:一个简单的以太坊游戏智能合约模板

    区块链游戏正在成为一种新兴的游戏形式,其中代币化的游戏资产成为了一个重要的组成部分。今天,我们将介绍一个简单的ERC-721智能合约模板,这个模板可以帮助你在以太坊区块链上创建你自己的ERC-721代币,让你的游戏更有趣。 源码下载 ERC-721是一种免费的开放标准,它

    2024年02月07日
    浏览(57)
  • C++多线程学习(九、不安全的队列测试,简单封装线程安全队列)

    目录 不安全的队列测试 简单封装一个线程安全队列 下方是一个简单的程序,但是不安全: 由于代码中的线程t是在后台运行的,所以无法确定线程t是否已经完成了对myQ队列的操作,因此在主线程中处理myQ队列时,可能会出现竞争条件或者数据不一致的情况,导致输出的结果

    2024年02月13日
    浏览(31)
  • 封装一个PHP可控限速下载文件的方法

    实测下载后的文件与源文件哈希值一致,保证数据传输安全一致。 如果下载到的文件每次都165KB左右,和源文件大小不符合,需要用IDE打开下载的文件,看看是否报致命错误,提示超过最大内存限制。这个与php.ini中的“memory_limit”参数配置有关,所以方法的$kilobyte参数不要设

    2024年02月08日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包