当前位置:C++技术网 > 资讯 > 创建多级目录多级文件夹三种实现方法全面解析

创建多级目录多级文件夹三种实现方法全面解析

更新时间:2015-06-26 23:13:42浏览次数:1+次

    创建多级目录,就是给出一个路径,如果中间含有的路径中包含多个目录,且不存在,则自动创建多级路径。

    我所了解到的,可以用三种方法创建多级目录。下面分别来介绍一番。【目录和文件夹是同一个意思】
    1.【ANSII版本】直接调用创建多级目录API函数MakeSureDirectoryPathExists
    使用此函数,首先需要包含头文件Dbghelp.h,如#include <Dbghelp.h>。同时还要导入lib库Dbghelp.lib。导入lib库可以在VS菜单“项目”->“属性”->“配置属性”->“链接器”->“输入”->“附加依赖项”中,输入“Dbghelp.lib.”即可。另外一个是使用预编译指令【#pragma comment(lib,"Dbghelp.lib")】即可。如果不导入lib库,会提示无法解析的外部符号。如果不包含头文件,则提示找不到MakeSureDirectoryPathExists标识符。
    函数MakeSureDirectoryPathExists的声明如下:
BOOL WINAPI MakeSureDirectoryPathExists(PCSTR DirPath);
    此函数用于创建指定的路径中所有的目录。也就是我们要的多级目录。此函数的名字叫做确保文件夹路径存在,也就是说,如果给定了文件夹,如果存在的目录则忽略,不存在的就全部创建,给定的含有多级不存在的目录都会被创建出来,保证这个给定的路径一定是存在的。此函数只有一个参数,参数的类型是PCSTR,此参数是const char *类型,表示此参数不会被函数修改。同时也表明,此参数不能是Unicode编码的字符串。使用前要将Unicode编码的字符串正确的转换为ANSII编码的字符串,否则路径就是乱码。
    此函数只创建文件夹,不创建文件。传入的文件路径如果以文件夹结束,则需要用\作为结束,比如d:\aa\bb\,这样才会创建aa文件夹,并在aa文件夹中创建bb文件夹,如果是d:\aa\bb,则是会创建aa文件夹。当然,你可以直接传入一个文件名的路径,如d:\aa\bb\1.txt,函数会自动提取其中的路径,然后创建没有的文件夹,但是不会创建文件。这样就创建了aa文件夹,且在aa中创建了bb文件夹。
    如果参数中的目录都存在或者如果函数参数中的目录不存在,且每一个目录都会被创建,则表示创建成功。如果有目录不存在,且只创建了不存在的目录的部分或者一个也没有创建,表示创建失败,返回FALSE。
    路径可以是相对路径,也可以是绝对路径。
    特别要注意的一点,MSDN特别提示,所有的DbgHelp函数,都是单线程的。MakeSureDirectoryPathExists函数是其中一个,也是单线程的。如果多个线程同时调用,可能出现异常的行为或者内存错误。所以如果要在多个线程都会用到,要做好同步工作,避免此函数在多个线程中同时执行。单线程中是不会出问题的。
    函数只返回真或者假,所以只需要判断返回值就可以知道是否执行成功。使用很简单,所以就不列举代码了。
    2.【Unicode和ANSII版本】
    Unicode的版本指的是传入的路径是Unicode编码的。第一种方法要处理Unicode版本路径,需要事先转换,如果转换不正确,会导致出现乱码,就会导致创建多级目录失败。此版本可以很好的解决此问题。
此版本的函数在网上查没有查到,不知道为什么,反正很难找到。然后就在MSDN中发现了此函数的存在。所以,我也是醉了,我也就总结一篇供大家参考学习。
    此函数是Windows Shell函数,名字为SHCreateDirectoryEx。此函数完成的功能和MakeSureDirectoryPathExists一样,不同的是它可以处理Unicode路径名,同时会返回详细的错误信息等。
    函数SHCreateDirectoryEx的声明如下:
int SHCreateDirectoryEx(HWND hwnd,LPCTSTR pszPath,const SECURITY_ATTRIBUTES *psa);
    此函数有三个参数,第一个是一个窗口句柄。在创建目录时,如果路径名不可见,会用消息框提示“可能不允许访问”,如果用户选择不处理,则函数会返回ERROR_CANCELLED,表示取消。而消息框就是以传入的句柄窗口作为父窗口而弹出的。如果设置句柄为空,遇见不可见隐藏的文件夹则不提示,直接返回ERROR_CANCELLED。
    第二个参数是路径名,既可以是ANSII版本的字符串路径,也可以是Unicode版本的字符串路径。此函数会创建此路径中不存在的所有目录。路径最大字符数为248个,包括结尾的空字符。注意这里是以字符计算的,不是字节。路径必须是全路径,否则创建失败。路径名参数中不管是以\结尾还是不以\结尾,都可以,都会被创建为文件夹。此函数不会创建文件。比如D:\aa\bb\或者D:\aa\bb,都会创建aa目录,然后在aa目录中创建bb目录。如果是D:\aa\bb.txt,那么会在aa目录中创建目录名为bb.txt的目录,而不是文件哦。
    第三个参数是目录的安全属性,一般就忽略它,直接传入NULL即可。
    函数的返回值有六种,分别如下:
ERROR_BAD_PATHNAME 错误:路径参数为相对路径. 
ERROR_FILENAME_EXCED_RANGE 错误:路径太长,超过了248个字符。 
ERROR_PATH_NOT_FOUND 错误:系统找不到参数中的路径,错误的驱动器(盘符)。比如系统没有G盘,传入一个G盘下的路径。 
ERROR_FILE_EXISTS 目录已经存在。MSDN上如此解释,但是目录真正存在返回的是ERROR_ALREADY_EXISTS。
ERROR_ALREADY_EXISTS 目录已经存在。
ERROR_CANCELLED 用户取消了操作。
    此函数使用的代码示例如下:
int iRetCode = SHCreateDirectoryEx(NULL,L"D:\\1\\2\\1.txt",NULL);
switch(iRetCode)
{
   case ERROR_BAD_PATHNAME:MessageBox(_T("不能为相对路径"));break;
   case ERROR_FILENAME_EXCED_RANGE:MessageBox(_T("路径名不能超过248个字符"));break;
   case ERROR_PATH_NOT_FOUND:MessageBox(_T("驱动器(盘符)不存在"));break;
   case ERROR_FILE_EXISTS:MessageBox(_T("文件已经存在"));break;
   case ERROR_ALREADY_EXISTS:MessageBox(_T("已经存在"));break;
   case ERROR_CANCELLED:MessageBox(_T("用户取消了操作"));break;
}

    3.【自己写多层目录创建函数】【Unicode和ANSII版本】
    这个方法,表示你不想用上述的两种方法来创建,那么你可以使用API函数CreateDirectory来一级一级的创建目录,此函数就不仔细讲解了,不清楚的可以参看MSDN。此函数比较常见,网上会有很多文章介绍。但是建议看MSDN,很全面,不会被网上一些文章误导。我自己整理了一些代码,借鉴了一下网上的代码,整理给大家参考。经过整理和注释说明,大家可以直接拿去使用。
    代码如下(需要包含头文件,#include "shlwapi.h"):
BOOL CreateMultiDirectory(CString strPath)
{
    CString strSubPath;
    CString strMsg;
    int nCount = 0; 
    int nIndex = 0;

    //通过“\”来分割路径,从而创建各级的目录。
    do
    {
        nIndex = strPath.Find(_T("\\"),nIndex) + 1;
        nCount++;
    }while( (nIndex-1) != -1);
    nIndex = 0;
    //检查,并创建目录
    while( (nCount-1) >= 0)
    {
        nIndex = strPath.Find(_T("\\"),nIndex) + 1;
        if( (nIndex - 1) == -1)
            strSubPath = strPath;
        else
            strSubPath = strPath.Left(nIndex);

        if(!PathFileExists(strSubPath))// - 检查目录是否存在
        {
            if(!CreateDirectory(strSubPath,NULL))// -不存在则创建目录
            {
                strMsg.Format(_T("创建目录【%s】失败!"),strSubPath);
                AfxMessageBox(strMsg,MB_OK);
                return FALSE;
            }
        }
        nCount--;
    };
    return TRUE;
}