如何安全的保存数据到文件 void SaveSetting (const char* strFile, const char* pBuffer, int nLength) { FILE * pFL = fopen ("c://setting.txt", "w+") ; fwrite (pBuffer, 1, nLength, pFL) ; fclose (pFL) ; } 有问题吗?绝大部分人会认为没错,对,确实没错@_@。。。先别仍鸡蛋。让我们考虑这样一种情况:在写文件的时候遇到断电或死机等异常退出,那目标文件就会不完整,要是配置信息这样的重要文件,损坏后可能就导致程序运行不了。也许有人会说这是杞人忧天,写文件也就几十毫秒,被中断的概率不亚于中彩票。。。最开始我也没怀疑到,但很高兴上帝如此偏爱我,总是让我偶尔(尤其关机时)又不可重现的碰到这种情况。而且,随着配置信息的增多,中奖概率也在上升。很多时候,越是这种看不上眼的小东西就越容易被人忽视。 /// 定义 class FCSafeSaveFile { public: FCSafeSaveFile (LPCTSTR szFilename, bool bSameExt=false) ; ~FCSafeSaveFile() ; bstr_t GetTempFilename() const ; void ReplaceFile() ; void DisableReplace() ; void EnableReplace() ; private: bstr_t m_strDest ; bstr_t m_strTemp ; BOOL m_bHasReplace ; }; /// 构造函数,在同一目录生成一个临时文件。 FCSafeSaveFile::FCSafeSaveFile (LPCTSTR szFilename, bool bSameExt=false) { m_strDest = szFilename ; m_bHasReplace = FALSE ; // get temp path TCHAR szPath[MAX_PATH], szDriver[_MAX_DRIVE], szDir[MAX_PATH] ; ::_tsplitpath (szFilename, szDriver, szDir, NULL, NULL) ; ::_tmakepath (szPath, szDriver, szDir, NULL, NULL) ; // get a temp filename TCHAR szTmp[MAX_PATH] ; ::GetTempFileName (szPath, _T("foo"), 0, szTmp) ; m_strTemp = szTmp ; if (bSameExt) { TCHAR szExt[_MAX_EXT] ; ::_tsplitpath (szFilename, NULL, NULL, NULL, szExt) ; bstr_t strNew = m_strTemp + szExt ; ::_trename (m_strTemp, strNew) ; m_strTemp = strNew ; } } /// 安全替换文件,请确认所有作用于临时文件的句柄都已关闭 void FCSafeSaveFile::ReplaceFile() { // delete exist file if (!PathFileExists(m_strDest)) { // rename ::_trename (m_strTemp, m_strDest) ; } else { ::SetFileAttributes (m_strDest, FILE_ATTRIBUTE_NORMAL) ; if (::DeleteFile (m_strDest)) { // rename ::_trename (m_strTemp, m_strDest) ; } else { assert(false) ; ::DeleteFile (m_strTemp) ; } } m_bHasReplace = TRUE ; } /// 没有人希望被要求必须调用 ReplaceFile,我们交给编译器和析构来做这事 FCSafeSaveFile::~FCSafeSaveFile() { ReplaceFile() ; if (PathFileExists(m_strTemp)) { assert(false) ; ::DeleteFile (m_strTemp) ; assert (!PathFileExists(m_strTemp)) ; } }现在我们可以用我们的类修改上面的代码,让它更安全: void SaveSetting (const char* strFile, const char* pBuffer, int nLength) { FCSafeSaveFile ssf (TEXT("c://setting.txt")) ; FILE * pFL = fopen (ssf.GetTempFilename(), "w+") ; fwrite (pBuffer, 1, nLength, pFL) ; fclose (pFL) ; }这样,我们就保证了目标文件的安全 似乎很完美了,考虑一个问题,如果你的代码维护者不清楚这段代码作用,在其中加入了一些return语句中途返回,文件替换操作还是会被执行,还是不完整。 void SaveSetting (const char* strFile, const char* pBuffer, int nLength) { FCSafeSaveFile ssf (TEXT("c://setting.txt")) ; ssf.DisableReplace() ; if (nLength != 10) return ; FILE * pFL = fopen (ssf.GetTempFilename(), "w+") ; fwrite (pBuffer, 1, nLength, pFL) ; fclose (pFL) ; ssf.EnableReplace() ; } 这样我们就从结构上尽量避免了维护者可能带来的问题。 这里,我们封装了一个非常非常简单的类,但它很有用,作为构建高层软件的基础,它能帮您省却今后的很多麻烦。
|
如何安全的保存数据到文件
最新推荐文章于 2022-06-22 14:53:06 发布