注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

多多的爹

 
 
 

日志

 
 

深入解析MFC -- MFC中的File类  

2008-01-25 19:49:42|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

MFC中大概有四种File类,分别是CFile,CStdioFile,CMemFile和CMirrorFile。前三种大家比较熟悉,最后一种比较少见。
CFile是对基本的io操作的封装,主要将Windows的文件API做了封装。其余三个类都从CFile派生。CStdioFile操作的对象是字符串,读写文本文件时经常用到。CMemFile是将内存当作文件操作,因此Open其实是申请一段内存,Close是释放内存。CMirrorFile比较有意思,值得一说。下面是CMirrorFile的声明和实现:
class CMirrorFile : public CFile
{
// Implementation
public:
    virtual void Abort();
    virtual void Close();
    virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL);
protected:
    CString m_strMirrorName;
};

BOOL CMirrorFile::Open(LPCTSTR lpszFileName, UINT nOpenFlags,  CFileException* pError)
{
    ASSERT(lpszFileName != NULL);
    m_strMirrorName.Empty();

    CFileStatus status;
    if (nOpenFlags & CFile::modeCreate) //opened for writing
    {
        if (CFile::GetStatus(lpszFileName, status))
        {
            CString strRoot;
            AfxGetRoot(lpszFileName, strRoot);

            DWORD dwSecPerClus, dwBytesPerSec, dwFreeClus, dwTotalClus;
            int nBytes = 0;
            if (GetDiskFreeSpace(strRoot, &dwSecPerClus, &dwBytesPerSec, &dwFreeClus,
                &dwTotalClus))
            {
                nBytes = dwFreeClus*dwSecPerClus*dwBytesPerSec;
            }
            if (nBytes > 2*status.m_size) // at least 2x free space avail
            {
                // get the directory for the file
                TCHAR szPath[_MAX_PATH];
                LPTSTR lpszName;
                GetFullPathName(lpszFileName, _MAX_PATH, szPath, &lpszName);
                *lpszName = NULL;

                //let's create a temporary file name
                GetTempFileName(szPath, _T("MFC"), 0,
                    m_strMirrorName.GetBuffer(_MAX_PATH+1));
                m_strMirrorName.ReleaseBuffer();
            }
        }
    }

    if (!m_strMirrorName.IsEmpty() &&
        CFile::Open(m_strMirrorName, nOpenFlags, pError))
    {
        m_strFileName = lpszFileName;
        FILETIME ftCreate, ftAccess, ftModify;
        if (::GetFileTime((HANDLE)m_hFile, &ftCreate, &ftAccess, &ftModify))
        {
            AfxTimeToFileTime(status.m_ctime, &ftCreate);
            SetFileTime((HANDLE)m_hFile, &ftCreate, &ftAccess, &ftModify);
        }

        DWORD dwLength = 0;
        PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
        if (GetFileSecurity(lpszFileName, DACL_SECURITY_INFORMATION,
            NULL, dwLength, &dwLength))
        {
            pSecurityDescriptor = (PSECURITY_DESCRIPTOR) new BYTE[dwLength];
            if (::GetFileSecurity(lpszFileName, DACL_SECURITY_INFORMATION,
                pSecurityDescriptor, dwLength, &dwLength))
            {
                SetFileSecurity(m_strMirrorName, DACL_SECURITY_INFORMATION, pSecurityDescriptor);
            }
            delete[] (BYTE*)pSecurityDescriptor;
        }
        return TRUE;
    }
    m_strMirrorName.Empty();
    return CFile::Open(lpszFileName, nOpenFlags, pError);
}

void CMirrorFile::Abort()
{
    CFile::Abort();
    if (!m_strMirrorName.IsEmpty())
        CFile::Remove(m_strMirrorName);
}

void CMirrorFile::Close()
{
    CString strName = m_strFileName; //file close empties string
    CFile::Close();
    if (!m_strMirrorName.IsEmpty())
    {
        BOOL (__stdcall *pfnReplaceFile)(LPCTSTR, LPCTSTR, LPCTSTR, DWORD, LPVOID, LPVOID);

        HMODULE hModule = GetModuleHandle(_T("KERNEL32"));
        ASSERT(hModule != NULL);

        pfnReplaceFile = (BOOL (__stdcall *)(LPCTSTR, LPCTSTR, LPCTSTR, DWORD, LPVOID, LPVOID))
#ifndef _UNICODE
            GetProcAddress(hModule, "ReplaceFileA");
#else
            GetProcAddress(hModule, "ReplaceFileW");
#endif

        if(!pfnReplaceFile || !pfnReplaceFile(strName, m_strMirrorName, NULL, 0, NULL, NULL))
        {
            CFile::Remove(strName);
            CFile::Rename(m_strMirrorName, strName);
        }
    }
}
从以上代码可以看到,CMirrorFile实际上提供了一个文件副本,所有的读写操作都是针对这个副本文件的,如果最后此文件没有被写入磁盘,则只删除副本文件。如果写入,则用副本文件替代原文件。
CMirrorFile的应用在哪里?打开C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\src\mfc\doccore.cpp,找到CDocument::GetFile,hoho,看到了吧。当要写文件时,有可能发生错误,在不破坏原有文件的情况下,就可以使用CMirrorFile。

  评论这张
 
阅读(15)| 评论(4)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017