首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C/C++ 獲取可執行文件路徑並創建同名目錄:Windows API 實戰

     編輯:關於C++

需求場景

MFC/控制台程序啟動時,需在可執行文件所在目錄下創建同名文件夾存放數據。例如 D:\KFS\codes\22222\Release\22222.exe → 創建 D:\KFS\codes\22222\Release\22222\。

核心 API:GetModuleFileName

DWORD GetModuleFileName(
    HMODULE hModule,    // NULL = 當前進程的 .exe
    LPSTR lpFilename,   // 接收路徑的緩衝區
    DWORD nSize         // 緩衝區大小
);
  • 返回完整路徑(含文件名),如 D:\Path\To\Program.exe
  • Unicode 版為 GetModuleFileNameW,返回 wchar_t*

完整實現代碼

#include <windows.h>
#include <iostream>
#include <io.h>
#include <string>
#include <direct.h>  // _mkdir

using namespace std;

int main() {
    char exePath[MAX_PATH];
    // 獲取可執行文件完整路徑
    GetModuleFileNameA(NULL, exePath, MAX_PATH);
    cout << "EXE 路徑: " << exePath << endl;

    // 提取目錄路徑 + 文件名(不含擴展名)
    string fullPath(exePath);
    size_t lastSlash = fullPath.find_last_of("\\/");
    size_t lastDot = fullPath.find_last_of('.');

    string dirPath = fullPath.substr(0, lastSlash + 1);           // 目錄(含尾部斜槓)
    string exeName = fullPath.substr(lastSlash + 1, lastDot - lastSlash - 1); // 純文件名
    string targetDir = dirPath + exeName;                         // 目標文件夾完整路徑

    cout << "目標文件夾: " << targetDir << endl;

    // 創建目錄(存在則不報錯)
    if (_access(targetDir.c_str(), 0) == -1) {
        if (_mkdir(targetDir.c_str()) == 0) {
            cout << "創建成功!" << endl;
        } else {
            cerr << "創建失敗: " << strerror(errno) << endl;
        }
    } else {
        cout << "目錄已存在。" << endl;
    }

    // 演示:在目標目錄創建測試文件
    string testFile = targetDir + "\\test.txt";
    FILE* fp = fopen(testFile.c_str(), "w");
    if (fp) {
        fprintf(fp, "Hello from %s\n", exeName.c_str());
        fclose(fp);
        cout << "測試文件已寫入。" << endl;
    }

    return 0;
}

關鍵技術點詳解

1. 字符集問題(Unicode vs ANSI)

VS 默認 Unicode 字符集,GetModuleFileName 映射為 GetModuleFileNameW,參數需 wchar_t*。解決方案:

  • 方案 A:項目屬性 → 字符集 → 「未設置」(使用 ANSI 版 API,如上代碼)
  • 方案 B:顯式調用 GetModuleFileNameW + wstring + _wmkdir / _waccess
  • 方案 C:使用 TCHAR、_T() 宏,配合 GetModuleFileName 自動適配

2. 路徑解析健壯性

// 更安全的路徑分離(處理無擴展名、根目錄等邊界情況)
#include <shlwapi.h>  // 需鏈接 Shlwapi.lib
#pragma comment(lib, "Shlwapi.lib")

char dir[MAX_PATH], fname[MAX_PATH], ext[MAX_PATH];
PathRemoveFileSpecA(exePath);  // 就地截取目錄
strcpy_s(dir, exePath);
PathStripPathA(exePath);       // 就地提取文件名
PathRemoveExtensionA(exePath); // 就地去擴展名
strcpy_s(fname, exePath);
// 目標路徑 = dir + "\\" + fname

3. 跨平台替代方案

// C++17 std::filesystem (GCC 8+, MSVC 19.14+, Clang 7+)
#include <filesystem>
namespace fs = std::filesystem;

fs::path exePath = fs::canonical("/proc/self/exe");  // Linux
// fs::path exePath = fs::canonical(GetModuleFileName...); // Windows
fs::path targetDir = exePath.parent_path() / exePath.stem();
fs::create_directories(targetDir);

常見坑點總結

問題原因解決
編譯錯誤 C2664Unicode 字符集下 LPSTR/LPWSTR 不匹配改字符集或用 W 版 API
路徑截斷MAX_PATH (260) 限制用 GetModuleFileNameW + 大緩衝區或 \\?\ 前綴
創建失敗權限不足、路徑包含非法字符檢查 errno、轉義路徑
相對路徑錯誤工作目錄非 EXE 目錄始終用 GetModuleFileName 獲取絕對路徑

總結

Windows 下 GetModuleFileName + 字符串處理是標準做法;現代 C++ 首選 std::filesystem 實現跨平台、類型安全、異常安全的路徑操作。理解字符集機制是避免編譯錯誤的關鍵。

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