C++中路径操作

1.获取当前应用程序所在路径

1.1 方法:GetModuleFileName

GetModuleFileName声明:

DWORD WINAPI GetModuleFileName(
_In_opt_  HMODULE hModule,
_Out_     LPTSTR lpFilename,
_In_      DWORD nSize
);

其中:
hModule —— 一个模块的句柄。可以是一个DLL模块,或者是一个应用程序的实例句柄。如果该参数为NULL,该函数返回该应用程序全路径;
lpFilename —— 指定一个字串缓冲区,要在其中容纳文件的用NULL字符中止的路径名;
nSize —— 装载到缓冲区lpFileName的最大字符数量。经常用_MAX_PATH;
_MAX_PATH是C语言运行时库中通过#define指令定义的一个宏常量,它定义了编译器所支持的最长全路径名的长度。在VC++6.0中,值为260;Windows SDK中也有一个相应的变量MAX_PATH,值也是260。

1.2 获取全路径后获取当前程序的运行目录(.exe)所在的目录

TCHAR exeFullPath[MAX_PATH + 1];
GetModuleFileName(NULL, atcExeFullPath, MAX_PATH);
CString path = atcExeFullPath;
path = path.Left(path.ReverseFind('\\'));

2.路径分解

2.1 方法:_tsplitpath_s

头文件:stdlib.h

_tsplitpath_s声明(不同编码方式下有不同的定义):

errno_t _splitpath_s(
   const char * path,
   char * drive,
   size_t driveNumberOfElements,
   char * dir,
   size_t dirNumberOfElements,
   char * fname,
   size_t nameNumberOfElements,
   char * ext,
   size_t extNumberOfElements
);
errno_t _wsplitpath_s(
   const wchar_t * path,
   wchar_t * drive,
   size_t driveNumberOfElements,
   wchar_t *dir,
   size_t dirNumberOfElements,
   wchar_t * fname,
   size_t nameNumberOfElements,
   wchar_t * ext,
   size_t extNumberOfElements
); 
template <size_t drivesize, size_t dirsize, size_t fnamesize, size_t extsize>  
errno_t _splitpath_s(  
   const char *path,  
   char (&drive)[drivesize],  
   char (&dir)[dirsize],  
   char (&fname)[fnamesize],  
   char (&ext)[extsize]  
); // C++ only  
template <size_t drivesize, size_t dirsize, size_t fnamesize, size_t extsize>  
errno_t _wsplitpath_s(  
   const wchar_t *path,  
   wchar_t (&drive)[drivesize],  
   wchar_t (&dir)[dirsize],  
   wchar_t (&fname)[fnamesize],  
   wchar_t (&ext)[extsize]  
); // C++ only

各个参数的意义:

[in] path:全路径
[out] drive:驱动器号,后跟一个冒号(:),如果你不需要驱动器号,可以传递NULL  
[in] driveNumberOfElements:Drive的缓冲区大小(单字节或宽字节),如果drive为NULL,该参数必须为0
[out] dir:目录路径,包括尾部的斜杠,可以使用“\”,“/”或者都使用,如果不需要目录路径,可以传递NULL
[in] dirNumberOfElements:Dir的缓冲区大小(单字节或者款字节),如果dir为NULL,该参数必须为0
[out] fname:不带扩展名的文件名,如果不需要文件名,可以传递NULL
[in] nameNumberOfElements:Fname的缓冲区大小(单字节或者宽字节),如果fname为NULL,该参数必须为0
[out] ext:文件的扩展名,包括“.”,如果不需要扩展名,可以传递NULL
[in] extNumberOfElements:Ext的缓冲区大小(单字节或者宽字节),如果ext为NULL,该参数必须为0

返回值:
    成功返回0,失败返回错误代码 EINVAL

EINVAL情形:
  (1) path为NULL;
  (2)drive、dir、fname、ext这四个缓冲区指针中存在NULL,但是缓冲区对应的NumberOfElements !=0;
  (3)drive、dir、fname、ext这四个缓冲区对应的NumberOfElements =0,但是缓冲区指针不为NULL。
补充:
  如果任何一个缓冲区太短而无法包含结果,那么该函数会清空所有缓冲区指向空。设置errno 为ERANGE,并返回ERANGE。

2.2各部分允许最大值

  该函数将全路径分割成四个部分,分别是驱动器,路径名,文件名(不带扩展名),扩展名。C语言运行时库定义的每个部分允许的最大值为分别为_MAX_DRIVE, _MAX_DIR, _MAX_FNAME, _MAX_EXT,而Window SDK中每个部分允许的最大值为分别为_MAX_DRIVE, _MAX_DIR, _MAX_FNAME, _MAX_EXT,这些宏定义在stdlib.h中,如果这四个部分的缓冲区大小超过了定义的允许的最大值,那么会引起 heap corruption.

CRT library与Windows SDK中定义的四个量对应相等,以下是四个宏的定义的最大值:
  _MAX_DRIVE  3
  _MAX_DIR   256
  _MAX_FNAME 256
  _Max_EXT   256

3.路径合成

3.1 方法:_tmakepath_s

头文件:stdlib.h

_tmakepath_s声明:

errno_t _makepath_s(  
   char *path,  
   size_t sizeInBytes,  
   const char *drive,  
   const char *dir,  
   const char *fname,  
   const char *ext   
);  
errno_t _wmakepath_s(  
   wchar_t *path,  
   size_t sizeInWords,  
   const wchar_t *drive,  
   const wchar_t *dir,  
   const wchar_t *fname,  
   const wchar_t *ext   
);  
template <size_t size>  
errno_t _makepath_s(  
   char (&path)[size],  
   const char *drive,  
   const char *dir,  
   const char *fname,  
   const char *ext   
); // C++ only  
template <size_t size>  
errno_t _wmakepath_s(  
   wchar_t (&path)[size],  
   const wchar_t *drive,  
   const wchar_t *dir,  
   const wchar_t *fname,  
   const wchar_t *ext   
); // C++ only

各个参数的意义:

[out] path:完整路径缓冲区。
[in] sizeInWords:缓冲区大小(以单词为单位)。
[in] sizeInBytes:缓冲区的大小(以字节为单位)。
[in] drive:包含一个与所需的驱动器对应的字母(A、B 等)和可选的尾随冒号。 如果缺少冒号,则 _makepath_s 会自动在复合路径中插入冒号。 如果 drive 为 NULL 或指向空字符串,则在复合 path 字符串中不会显示驱动器号。
[in] dir:包含目录路径,但不包括驱动器指示符或实际文件名。 尾随斜杠是可选的和正斜杠 (/) 或反斜杠 (\) 或两者可能使用在单个dir参数。 如果尾部反斜杠 (/ 或\) 指定,则它将自动进行插入。 如果 dir 为 NULL 或指向空字符串,则在复合 path 字符串中不会插入目录路径。
[in] fname:包含无任何文件扩展名的基文件名。 如果 fname 为 NULL 或指向空字符串,则在复合 path 字符串中不会插入文件名。
[in] ext:包含实际的文件扩展名(带有或不带前导句点 (.))。 如果 _makepath_s 中未显示句点,则 ext 会自动插入句点。 如果 ext 为 NULL 或指向空字符串,则在复合 path 字符串中不会插入扩展名。

// 取得当前应用程序所在路径,包括程序文件名与后缀名
TCHAR drive[_MAX_DRIVE], dir[MAX_PATH], fname[MAX_PATH], ext[_MAX_EXT];
TCHAR exeFullPath[MAX_PATH];
GetModuleFileName(NULL, exeFullPath, MAX_PATH);
//分解
_tsplitpath_s(exeFullPath, drive, dir, fname, ext);  
// 去掉应用程序文件名与后缀名
TCHAR exeFullDir[MAX_PATH];
//合并
_tmakepath_s(exeFullDir, drive, dir, _T(""), _T(""));