为什么在MFC中无法在创建和写入模式下打开隐藏文件?

时间:2018-03-09 04:30:45

标签: c++ mfc

我正在使用Visual C ++ 2010& MFC写了一个小程序。

以下是我的代码:

        CFile MyFile;
        CFileException* pException = NULL;
        CString strErrorMessage;
        //  The Test.txt is a hidden file that I created already.
        if (!MyFile.Open(_T("E:\\Test.txt"), CFile::modeWrite | CFile::modeCreate, pException))
        {
            TCHAR lpCause[255];
            pException->GetErrorMessage(lpCause, 255);
            strErrorMessage += lpCause;
        }
        //  ...
        //  rewrite the Test.txt
        //  ...
        MyFile.Close(); 

以下是我的问题:

1.运行代码时,会出现未处理的异常。那么如何修改代码才能使其正常工作?

2.我尝试删除Test.txt隐藏文件属性,似乎运行良好。我想知道:为什么文件隐藏属性的文件(已存在)无法在创建和写入模式下打开?

感谢。

1 个答案:

答案 0 :(得分:3)

pException仅初始化为NULL,未分配。您应该分配它,或者只是声明CFileException exception;并传递地址&exception。另外,如果CFile::Open失败,请勿尝试关闭文件。

CFile的文档说不要将CFile::modeCreate用于现有文件,因为它会引发异常。推理并不完全正确。

在Visual Studio 15中,MFC的CFile::Open源代码显示:

// map creation flags
if (nOpenFlags & modeCreate)
{
    if (nOpenFlags & modeNoTruncate)
        dwCreateFlag = OPEN_ALWAYS;
    else
        dwCreateFlag = CREATE_ALWAYS;
}
else
    dwCreateFlag = OPEN_EXISTING;
...
CreateFile(... nOpenFlags ...)

CFile::modeCreate(不modeNoTruncate)在CREATE_ALWAYS API中设置标记CreateFileCreateFile的WinAPI文档说

  

如果指定了CREATE_ALWAYSFILE_ATTRIBUTE_NORMALCreateFile   如果文件失败,则将最后一个错误设置为ERROR_ACCESS_DENIED   已存在且有FILE_ATTRIBUTE_HIDDENFILE_ATTRIBUTE_SYSTEM   属性。要避免错误,请指定与之相同的属性   现有文件。

这解释了为什么函数仅对存在和隐藏的文件失败。

要解决此问题,我们可以添加modeNoTruncate以强制OPEN_ALWAYS。如果需要,请使用CFile::SetLength(0)截断文件。

CFile MyFile;
CFileException exception;
CString strErrorMessage;
CString filename = _T("e:\\Test.txt");

if(MyFile.Open(filename, CFile::modeWrite | CFile::modeCreate | CFile::modeNoTruncate, 
    &exception))
{
    //SetLength(0) if file needs to truncate
    MyFile.SetLength(0);
    MyFile.Close();
}
else
{
    TCHAR lpCause[255];
    exception.GetErrorMessage(lpCause, 255);
    strErrorMessage += lpCause;
}

或者,测试是否存在旧文件,如果文件不存在则添加CFile::modeCreate。再后跟SetLength(0)截断文件。

UINT flags = CFile::modeWrite;
if(!PathFileExists(filename))
    flags |= CFile::modeCreate;
if (MyFile.Open(filename, flags, &exception))
{
    MyFile.SetLength(0);
    MyFile.Close();
}