功能设计:设计一种自定义三维格式,可以接受常见的三维模型数据,主要包括几何数据、属性数据及纹理材质数据。其中几何数据以.dat后缀的二进制数据来进行存储;属性数据以.csv的表格形式来存储;纹理材质图片保存到文件夹内;
CFileManager.h
#pragma once
#include "ModelData.h"
class CFileManager
{
public:
CFileManager();
~CFileManager();
void Save(PCTSTR szPath) const;
bool Load(PCTSTR szPath);
const char* GetFileMagic() const;
UINT GetVersion() const;
// 当Load()返回false后,获取错误信息
CString GetErrorStr() const;
CModelDataArray m_aryModelData; // 模型数据
private:
// 文件头
static const char s_fileMagic[4];
// 版本号
const unsigned int m_version;
CString m_strError;
};
CFileManager.cpp
#include "StdAfx.h"
#include "FileManager.h"
const char CFileManager::s_fileMagic[4] = { 'A','B','C','D' };
CFileManager::CFileManager()
: m_version(100) // 大版本升级加100,小版本升级加1
{
}
CFileManager::~CFileManager()
{
}
const char* CFileManager::GetFileMagic() const
{
return s_fileMagic;
}
UINT CFileManager::GetVersion() const
{
return m_version;
}
CString CFileManager::GetErrorStr() const
{
return m_strError;
}
void CFileManager::Save(PCTSTR szPath) const
{
// 写入二进制数据
CString strFileName = (CString)szPath + _T("\\model.dat");
std::ofstream wFile(strFileName, 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 nModelCount = (UINT)m_aryModelData.size();
wFile.write(reinterpret_cast<char*>(&nModelCount), sizeof(UINT));
if (nModelCount > 0)
{
for (UINT i = 0; i < nModelCount; i++)
{
m_aryModelData[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 CFileManager::Load(PCTSTR szPath)
{
// 读取二进制数据
CString strFileName = (CString)szPath + _T("\\model.dat");
m_strError.Empty();
std::ifstream iFile(strFileName, 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 nModelCount = 0;
iFile.read(reinterpret_cast<char*>(&nModelCount), sizeof(UINT));
if (nModelCount > 0)
{
m_aryModelData.clear();
m_aryModelData.reserve(nModelCount);
for (UINT i = 0; i < nModelCount; i++)
{
CModelData model;
model.Load(iFile);
m_aryModelData.push_back(model);
}
}
UINT64 uRealen = (UINT64)iFile.tellg() - (UINT64)nHeaderSize;
if (uRealen != uTotalLen)
{
m_strError.Format(_T("记录的数据长度%I64u与实际值%I64u不匹配!"), uTotalLen, uRealen);
return false;
}
return true;
}