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;
}