在 Windows 下,C++ 可以通过 Win API 或者标准库来获取和设置当前目录,接下来将分别对其进行说明。
通过 WIN API 获取和设置当前目录
每个进程都有一个当前目录,它由两部分组成:
- 磁盘指示符,可以是驱动器号后跟冒号,或服务器名称后跟共享名 (\\servername\sharename)
- 磁盘指示符上的目录
多线程应用程序和共享库代码不应使用 GetCurrentDirectory 函数,并且应避免使用相对路径名。SetCurrentDirectory 函数写入的当前目录状态作为全局变量存储在每个进程中,因此,多线程应用程序无法可靠地使用此值,因为其他线程也可能正在读取或设置此值。此限制也适用于 SetCurrentDirectory 和 GetFullPathName 函数。
通过 WIN API 获取和设置当前目录的 API 如下
GetCurrentDirectory
GetCurrentDirectory 的函数原型如下:
| DWORD GetCurrentDirectory(DWORD  nBufferLength,
 LPTSTR lpBuffer
 );
 
 | 
- 参数
- nBufferLength: 当前目录字符串的缓冲区长度,以- TCHAR为单位。缓冲区长度必须包括终止空字符的空间
- lpBuffer: 指向接收当前目录字符串的缓冲区的指针。这个以空字符结尾的字符串指定了当前目录的绝对路径。要确定所需的缓冲区大小,请将此参数设置为- NULL,并将- nBufferLength参数设置为 0。
 
- 返回值
- 如果函数成功,则返回值指定写入缓冲区的字符数,不包括终止空字符
- 如果函数失败,则返回值为零。要获取错误信息,请调用 GetLastError
- 如果 lpBuffer指向的缓冲区不够大,则返回值指定缓冲区所需的大小,以字符为单位,包括空终止字符
 
SetCurrentDirectory
SetCurrentDirectory 的函数原型如下:
| BOOL SetCurrentDirectory(LPCTSTR lpPathName
 );
 
 | 
- 参数
- lpPathName: 新的当前目录的路径。此参数可以指定相对路径或完整路径。无论哪种情况,都会计算指定目录的完整路径并将其存储为当前目录。在此函数的 ANSI 版本中,名称限制为- MAX_PATH个字符。空字符之前的最后一个字符必须是反斜杠 (- '\')。如果你不指定反斜杠,它会为你添加;因此,除非包含尾部反斜杠,否则为路径指定- MAX_PATH-2个字符,在这种情况下,为路径指定- MAX_PATH-1个字符。
 
- 返回值
- 如果函数成功,则返回值非零
- 如果函数失败,则返回值为零。要获取扩展错误信息,请调用 GetLastError
 
Example
| #include <windows.h>#include <iostream>
 #include <format>
 
 #define BUFSIZE MAX_PATH
 
 std::wstring getCurrentDirectory()
 {
 TCHAR Buffer[BUFSIZE];
 DWORD dwRet;
 
 dwRet = GetCurrentDirectory(BUFSIZE, Buffer);
 if (dwRet == 0)
 {
 std::wcout << std::format(L"GetCurrentDirectory failed. error code: {}\n", GetLastError());
 return L"";
 }
 
 if (dwRet > BUFSIZE)
 {
 std::wcout << std::format(L"Buffer too small; need {} characters\n", dwRet);
 return L"";
 }
 
 std::wcout << std::format(L"Current directory is {} \n", Buffer);
 
 return Buffer;
 }
 
 int main()
 {
 auto oldCurDir = getCurrentDirectory();
 
 std::wstring newDir = LR"(C:\ProgramData)";
 
 if (!SetCurrentDirectory(newDir.c_str()))
 {
 std::wcout << std::format(L"SetCurrentDirectory failed. error code: {}", GetLastError());
 return -1;
 }
 std::wcout << std::format(L"set current directory to {}\n", newDir);
 auto CurDir = getCurrentDirectory();
 
 if (!SetCurrentDirectory(oldCurDir.c_str()))
 {
 std::wcout << std::format(L"SetCurrentDirectory failed. error code: {}\n", GetLastError());
 return -1;
 }
 std::wcout << std::format(L"Restore previous directory {}\n", oldCurDir);
 CurDir = getCurrentDirectory();
 
 return 0;
 }
 
 | 
通过标准库获取和设置当前目录
标准库 std::filesystem 中有处理当前目录的函数,设置和获取当前目录的函数名相同,其函数原型如下:
| path current_path();path current_path( std::error_code& ec );
 void current_path( const std::filesystem::path& p );
 void current_path( const std::filesystem::path& p, std::error_code& ec ) noexcept;
 
 | 
| #include <iostream>#include <format>
 #include <filesystem>
 
 namespace fs = std::filesystem;
 
 fs::path getCurrentDirectory()
 {
 std::error_code ec;
 auto path = fs::current_path(ec);
 if (ec)
 {
 std::cout << std::format("getCurrentDirectory failed. error: {}\n", ec.message());
 return fs::path{};
 }
 
 return path;
 }
 
 bool setCurrentDirectory(const fs::path& path)
 {
 std::error_code ec;
 fs::current_path(path, ec);
 if (ec)
 {
 std::cout << std::format("setCurrentDirectory failed. error : {}\n", ec.message());
 return false;
 }
 
 return true;
 }
 
 void testStdApi()
 {
 std::cout << std::format( "current directory: {}\n", getCurrentDirectory().string());
 std::wstring newDir = LR"(C:\ProgramData)";
 if (setCurrentDirectory(newDir))
 {
 std::cout << std::format("after set new directory.\n");
 std::cout << std::format("current directory: {}\n", getCurrentDirectory().string());
 }
 }
 
 int main()
 {
 testStdApi();
 return 0;
 }
 
 | 
程序输出为:
| current directory: D:\VS_Projects\Utilsafter set new directory.
 current directory: C:\ProgramData
 
 |