在 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\Utils after set new directory. current directory: C:\ProgramData
|