通用二进制文件的创建及读取

1、功能目的

将获取的管道数据和管点数据(均包含属性)保存为二进制文件,方便后续使用时候读取;相比XML和json格式,数据量很大时二进制存储和读取速度较快。包含整体的读写函数。

2、功能实例演示
在这里插入图片描述

//写入测试数据:
void CTestBinaryProDlg::OnBnClickedBtnWrite()
{
    
    
	// TODO: 在此添加控件通知处理程序代码
	CPipeDataPackage pipePackage;

	// 管线属性字段
	pipePackage.m_pipeFields.push_back(_T("管代号"));
	pipePackage.m_pipeFields.push_back(_T("工程直径"));
	pipePackage.m_pipeFields.push_back(_T("管材"));
	pipePackage.m_pipeFields.push_back(_T("管道起点标高"));
	pipePackage.m_pipeFields.push_back(_T("管道终点标高"));
	pipePackage.m_pipeFields.push_back(_T("敷设方式"));

	// 节点属性字段
	pipePackage.m_nodeFields.push_back(_T("节点编号"));
	pipePackage.m_nodeFields.push_back(_T("节点设计标高"));

	// 管线数据
	CString strObjId = _T("1_1_3");
	AcGePoint3d startPnt(10.0, 10.0,0.0);
	AcGePoint3d endPnt(10.0, 10.0,0.0);
	std::vector<CString> propValSet;
	propValSet.push_back(_T("JS"));
	propValSet.push_back(_T("200"));
	propValSet.push_back(_T("水泥"));
	propValSet.push_back(_T("89.3"));
	propValSet.push_back(_T("89.3"));
	propValSet.push_back(_T("直埋"));

	CPipeData pipeData(strObjId,startPnt,endPnt,propValSet);
	pipePackage.m_aryPipes.push_back(pipeData);

	// 节点数据
	CString strNodeObjId = _T("1_2_2");
	AcGePoint3d pntNodePos(15.0, 15.0,0.0);
	CString strNodeType = _T("检查井");
	std::vector<CString> propNodeValSet;
	propNodeValSet.push_back(_T("JS110"));
	propNodeValSet.push_back(_T("90.0"));

	CPipeNodeData nodeData(strNodeObjId, strNodeType, pntNodePos, propNodeValSet);
	pipePackage.m_aryPipeNodes.push_back(nodeData);

	CString strFileName;
	GetDlgItem(IDC_EDIT1)->GetWindowTextW(strFileName);
	strFileName += _T("\\js.dat");

	pipePackage.Save(strFileName);
}

// 读取验证数据
void CTestBinaryProDlg::OnBnClickedBtnRead()
{
    
    
	// TODO: 在此添加控件通知处理程序代码
	CPipeDataPackage pipePackage;
	CString strFileName;
	GetDlgItem(IDC_EDIT1)->GetWindowTextW(strFileName);
	strFileName += _T("\\js.dat");

	pipePackage.Load(strFileName);

	// 调试查看验证数据
	std::vector<CString>& pipeFields = pipePackage.m_pipeFields; // 管线属性字段集
	CPipeDataArray& aryPipes = pipePackage.m_aryPipes;

	std::vector<CString> nodeFields = pipePackage.m_nodeFields; // 节点属性字段集
	PipeNodeDataArray aryPipeNodes = pipePackage.m_aryPipeNodes;
}

3、实现方式

头文件.h

// 管道几何数据与属性
class CPipeData
{
    
    
public:
	CPipeData();

	CPipeData(const CString& strObjId, const AcGePoint3d& startPnt, const AcGePoint3d& endPnt, const std::vector<CString>& propValSet);

	~CPipeData();

	void Save(std::ofstream& fileStream) const;

	void Load(std::ifstream& fileStream);

	AcGePoint3d m_posBgn;
	AcGePoint3d m_posEnd;
	CString m_strBatchId; // 模型的ObjId
	std::vector<CString> m_strPropVals;
};

typedef std::vector<CPipeData> CPipeDataArray;

// 节点几何数据与属性
class CPipeNodeData
{
    
    
public:
	CPipeNodeData();

	CPipeNodeData(const CString& strObjId, CString strNodeType,const AcGePoint3d& nodePnt, const std::vector<CString>& propValSet);

	~CPipeNodeData();

	void Save(std::ofstream& fileStream) const;

	void Load(std::ifstream& fileStream);

	AcGePoint3d m_posNode;
	CString m_strBatchId;  // 模型的ObjId
	CString m_strNodeType; // 节点类型
	std::vector<CString> m_strPropVals;
};

typedef std::vector<CPipeNodeData> PipeNodeDataArray;

// 包含一种子类型管线几何数据与属性的二进制数据包
class CPipeDataPackage
{
    
    
public:
	CPipeDataPackage();
	~CPipeDataPackage();

	void Save(PCTSTR szPath) const;

	bool Load(PCTSTR szPath);

	const char* GetFileMagic() const;

	UINT GetVersion() const;

	// 当Load()返回false后,获取错误信息
	CString GetErrorStr() const;

	std::vector<CString> m_pipeFields; // 管线属性字段集
	CPipeDataArray m_aryPipes;

	std::vector<CString> m_nodeFields; // 节点属性字段集
	PipeNodeDataArray m_aryPipeNodes;

private:
	// 文件头
	static const char s_fileMagic[4];
	// 版本号
	const unsigned int m_version;

	CString m_strError;
};

源代码.cpp

bool FbRead(std::ifstream& inFile, void* lpBuf, unsigned int nSize)
{
    
    
	if (inFile.is_open() == false)
		return false;

	inFile.read((char*)lpBuf, nSize);
	return inFile.good();
}

bool FbWrite(std::ofstream& outFile, void* lpBuf, unsigned int nSize)
{
    
    
	if (outFile.is_open() == false)
		return false;

	outFile.write((char*)lpBuf, nSize);
	return outFile.good();
}

// 由于读取写入都是UNICODE程序,因此省略了字符编码转换
void ReadString(std::ifstream& inFile, CString& strContent)
{
    
    
	std::string str = "";
	char ch;
	FbRead(inFile, &ch, 1);
	while (ch != '\0')
	{
    
    
		str.append(1, ch);
		FbRead(inFile, &ch, 1);
	}

	strContent = CString(str.c_str());
}

void WriteString(std::ofstream& outFile, const CString& strContent)
{
    
    
	CString strTemp = strContent;
	CStringA stra(strTemp.GetBuffer(0));
	strTemp.ReleaseBuffer();
	std::string str = stra.GetBuffer(0);
	stra.ReleaseBuffer();

	FbWrite(outFile, (void*)str.c_str(), (UINT)str.length() + 1); // 直接多写一个字符'\0'
}

CPipeData::CPipeData()
{
    
    
	m_strBatchId = _T("");
}

CPipeData::CPipeData(const CString& strObjId, const AcGePoint3d& startPnt, const AcGePoint3d& endPnt, const std::vector<CString>& propValSet)
{
    
    
	m_strBatchId = strObjId;
	m_posBgn = startPnt;
	m_posEnd = endPnt;
	m_strPropVals = propValSet;
}

CPipeData::~CPipeData()
{
    
    
}

void CPipeData::Save(std::ofstream& fileStream) const
{
    
    
	WriteString(fileStream, m_strBatchId);
	FbWrite(fileStream, (void*)&m_posBgn, sizeof(AcGePoint3d));
	FbWrite(fileStream, (void*)&m_posEnd, sizeof(AcGePoint3d));
	
	FbWrite(fileStream, (void*)m_vertices, sizeof(float)*m_vertexCount);
	
	int nPropsCount = static_cast<int>(m_strPropVals.size());
	FbWrite(fileStream, (void*)&nPropsCount, sizeof(int));
	for (auto itr = m_strPropVals.begin(); itr != m_strPropVals.end(); itr++)
	{
    
    
		WriteString(fileStream, *itr);
	}

	fileStream.flush();
}

void CPipeData::Load(std::ifstream& fileStream)
{
    
    
	if (fileStream.is_open() == false)
		return;

	ReadString(fileStream, m_strBatchId);
	FbRead(fileStream, &m_posBgn, sizeof(AcGePoint3d));
	FbRead(fileStream, &m_posEnd, sizeof(AcGePoint3d));
	int nCount = 0;
	FbRead(fileStream, &nCount, sizeof(int));
	m_strPropVals.resize(nCount);
	for (int i = 0; i < nCount ; i++)
	{
    
    
		ReadString(fileStream, m_strPropVals[i]);
	}
}

CPipeNodeData::CPipeNodeData()
{
    
    
	m_strBatchId = _T("");
}

CPipeNodeData::CPipeNodeData(const CString& strObjId, const CString strNodeType,const AcGePoint3d& nodePnt, const std::vector<CString>& propValSet)
{
    
    
	m_strBatchId = strObjId;
	m_strNodeType = strNodeType;
	m_posNode = nodePnt;
	m_strPropVals = propValSet;
}

CPipeNodeData::~CPipeNodeData()
{
    
    
}

void CPipeNodeData::Save(std::ofstream& fileStream) const
{
    
    
	if (fileStream.is_open() == false)
		return;

	WriteString(fileStream, m_strBatchId);
	WriteString(fileStream, m_strNodeType);
	FbWrite(fileStream, (void*)&m_posNode, sizeof(AcGePoint3d));
	int nPropsCount = static_cast<int>(m_strPropVals.size());
	FbWrite(fileStream, (void*)&nPropsCount, sizeof(int));
	for (auto itr = m_strPropVals.begin(); itr != m_strPropVals.end(); itr++)
	{
    
    
		WriteString(fileStream, *itr);
	}

	fileStream.flush();
}

void CPipeNodeData::Load(std::ifstream& fileStream)
{
    
    
	if (fileStream.is_open() == false)
		return;

	ReadString(fileStream, m_strBatchId);
	ReadString(fileStream, m_strNodeType);
	FbRead(fileStream, &m_posNode, sizeof(AcGePoint3d));
	int nCount = 0;
	FbRead(fileStream, &nCount, sizeof(int));
	m_strPropVals.resize(nCount);
	for (int i = 0; i < nCount; i++)
	{
    
    
		ReadString(fileStream, m_strPropVals[i]);
	}
}

const char CPipeDataPackage::s_fileMagic[4] = {
    
     'A','B','C','D' };

CPipeDataPackage::CPipeDataPackage()
	: m_version(100) // 大版本升级加100,小版本升级加1
{
    
    
}

CPipeDataPackage::~CPipeDataPackage()
{
    
    
}

void CPipeDataPackage::Save(PCTSTR szPath) const
{
    
    
	std::ofstream wFile(szPath, std::ios::binary);
	if (wFile.is_open() == false)
		return;
	
	wFile.write(s_fileMagic, 4);
	wFile.write(reinterpret_cast<const char*>(&m_version), sizeof(UINT));

	std::streampos fileSizePos = wFile.tellp();
	UINT64 uTotalLen = 0;
	wFile.write(reinterpret_cast<char*>(&uTotalLen), sizeof(UINT64)); // 管线数据长度,占位
	int nHeaderSize = 4 + sizeof(UINT) + sizeof(UINT64);

	UINT uCount = (UINT)m_aryPipes.size();
	wFile.write(reinterpret_cast<char*>(&uCount), sizeof(UINT));

	UINT uFields = 0;
	if (uCount > 0)
	{
    
    
		uFields = (UINT)m_pipeFields.size();
		wFile.write(reinterpret_cast<char*>(&uFields), sizeof(UINT));

		for (auto itr = m_pipeFields.begin(); itr != m_pipeFields.end(); itr++)
			WriteString(wFile, *itr);

		for (UINT i = 0; i < uCount; i++)
		{
    
    
			m_aryPipes[i].Save(wFile);
		}
	}

	uCount = (UINT)m_aryPipeNodes.size();
	wFile.write(reinterpret_cast<char*>(&uCount), sizeof(UINT));

	if (uCount > 0)
	{
    
    
		uFields = (UINT)m_nodeFields.size();
		wFile.write(reinterpret_cast<char*>(&uFields), sizeof(UINT));

		for (auto itr = m_nodeFields.begin(); itr != m_nodeFields.end(); itr++)
			WriteString(wFile, *itr);

		for (UINT i = 0; i < uCount; i++)
		{
    
    
			m_aryPipeNodes[i].Save(wFile);
		}
	}

	wFile.flush();
	std::streampos total = wFile.tellp();
	wFile.seekp(fileSizePos);
	uTotalLen = static_cast<UINT64>(total - (std::streampos)nHeaderSize);
	wFile.write(reinterpret_cast<char*>(&uTotalLen), sizeof(UINT64));
}

bool CPipeDataPackage::Load(PCTSTR szPath)
{
    
    
	m_strError.Empty();
	std::ifstream iFile(szPath, std::ios::binary);
	if (iFile.is_open() == false)
	{
    
    
		m_strError.Format(_T("加载文件%s失败!"), szPath);
		return false;
	}

	char cHeadpart[4] = {
    
     0 };
	iFile.read(cHeadpart, 4);
	for (int i = 0; i < 4; i++)
	{
    
    
		if (cHeadpart[i] != s_fileMagic[i])
		{
    
    
			m_strError.Format(_T("%s的文件头错误!"), szPath);
			return false;
		}
	}

	UINT thatVer = 0;
	iFile.read(reinterpret_cast<char*>(&thatVer), sizeof(UINT));

	if (thatVer == 0 || thatVer > m_version)
	{
    
    
		m_strError.Format(_T("文件%s的版本号错误!读取的版本号为%u,当前版本号为%u"), szPath, thatVer, m_version);
		return false;
	}

	UINT64 uTotalLen = 0;
	iFile.read(reinterpret_cast<char*>(&uTotalLen), sizeof(UINT64)); // 管线数据长度
	int nHeaderSize = 4 + sizeof(UINT) + sizeof(UINT64);

	UINT uCount = 0;
	iFile.read(reinterpret_cast<char*>(&uCount), sizeof(UINT));

	UINT uFields = 0;
	if (uCount > 0)
	{
    
    
		iFile.read(reinterpret_cast<char*>(&uFields), sizeof(UINT));
		m_pipeFields.resize(uFields);

		for (auto itr = m_pipeFields.begin(); itr != m_pipeFields.end(); itr++)
			ReadString(iFile, *itr);

		m_aryPipes.resize(uCount);
		for (UINT i = 0; i < uCount; i++)
		{
    
    
			m_aryPipes[i].Load(iFile);
		}
	}

	uCount = 0;
	iFile.read(reinterpret_cast<char*>(&uCount), sizeof(UINT));

	if (uCount > 0)
	{
    
    
		iFile.read(reinterpret_cast<char*>(&uFields), sizeof(UINT));
		m_nodeFields.resize(uFields);

		for (auto itr = m_nodeFields.begin(); itr != m_nodeFields.end(); itr++)
			ReadString(iFile, *itr);

		m_aryPipeNodes.resize(uCount);
		for (UINT i = 0; i < uCount; i++)
		{
    
    
			m_aryPipeNodes[i].Load(iFile);
		}
	}

	UINT64 uRealen = (UINT64)iFile.tellg() - (UINT64)nHeaderSize;
	if (uRealen != uTotalLen)
	{
    
    
		m_strError.Format(_T("记录的数据长度%I64u与实际值%I64u不匹配!"), uTotalLen, uRealen);
		return false;
	}

	return true;
}

const char* CPipeDataPackage::GetFileMagic() const
{
    
    
	return s_fileMagic;
}

UINT CPipeDataPackage::GetVersion() const
{
    
    
	return m_version;
}

CString CPipeDataPackage::GetErrorStr() const
{
    
    
	return m_strError;
}

猜你喜欢

转载自blog.csdn.net/m0_37251750/article/details/120056601