首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

MFC CFile 創建文件判斷「僅創建不覆蓋」的正確姿勢

     編輯:程式設計疑難解答

問題現象

CFile file;
BOOL ret = file.Open(_T("test.txt"), CFile::modeCreate | CFile::modeWrite);
// 文件已存在時:Open 成功返回 TRUE,但內容被截斷 (覆蓋)!
// 需求:文件存在 → 返回 FALSE,不修改文件。

原因分析

  • CFile::modeCreate 語義:**若無則創建,若有則打開並截斷 (truncate)**。
  • 這是標準 C/C++ fopen("w") / open(O_CREAT | O_TRUNC) 行為。
  • 無單一標志位實現「僅創建不覆蓋」(即 O_EXCL 效果)。

解決方案

方案一:預先檢查文件是否存在 (推薦,最清晰)

CString path = _T("test.txt");
if (PathFileExists(path)) { // 需 #include  並鏈接 Shlwapi.lib
    AfxMessageBox(_T("文件已存在!"));
    return FALSE;
}

CFile file;
if (!file.Open(path, CFile::modeCreate | CFile::modeWrite)) {
    return FALSE;
}
// 寫入數據...
file.Close();
return TRUE;

方案二:用 CFile::modeNoTruncate 組合 (不截斷,但指針在末尾)

// modeCreate | modeNoTruncate | modeWrite
// 文件不存在 → 創建
// 文件存在 → 打開,指針在文件末尾,寫入會追加
// 缺點:無法直接實現「存在即失敗」

方案三:Win32 API CreateFile 精確控制

HANDLE hFile = CreateFile(
    path, 
    GENERIC_WRITE, 
    0, NULL, 
    CREATE_NEW,        // 關鍵:CREATE_NEW = 僅創建,存在失敗 (ERROR_FILE_EXISTS)
    FILE_ATTRIBUTE_NORMAL, 
    NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
    if (GetLastError() == ERROR_FILE_EXISTS) {
        // 文件已存在
    }
    return FALSE;
}
// 寫入...
CloseHandle(hFile);

✅ 精確實現「原子性創建或失敗」,無競態條件。

方案四:CFile 繼承重寫 (高級)

class CMyFile : public CFile {
public:
    BOOL OpenExclusive(LPCTSTR lpszFileName) {
        // 內部調用 CreateFile CREATE_NEW
    }
};

最佳實踐建議

場景推薦方法
一般業務邏輯,單線程方案一 PathFileExists + CFile::Open
高併發、多進程搶佔創建方案三 CreateFile(CREATE_NEW) 原子操作
需追加寫入而非覆蓋modeCreate | modeNoTruncate | modeWrite

總結

CFile::Open 無原生「僅創建不覆蓋」標志。**單線程用 PathFileExists 預檢最簡單**;**多線程/進程必須用 Win32 CreateFile(CREATE_NEW) 保證原子性**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved