I was recently working on a C++/MFC application that needed to backup a bunch of files. Copying files is easy enough, but I had to create the target folder if it didn't exist. Creating a folder is also easy. However, CreateDirectory
will not create intermediate directories.
That is, if I need to create the directory D:\Documents\Financials, CreateDirectory()
will fail if D:\Documents does not already exist. To build this directory, I must first create D:\Documents before I can create D:\Documents\Financials. Clearly, I needed a routine that will ensure a path of any depth exists, and will create any missing folders.
Note that SHCreateDirectory
is documented as doing just this. However, the documentation also states this function "might be altered or unavailable in subsequent versions of Windows." I didn't really care for the sound of that so I decided to write my own routine. Although it required a little thought, the routine I came up with is reasonably simple and quite short.
Listing one shows my EnsurePathExists
routine. It takes a path string
, and will determine if it exists. If it does not exist, the routine will create it. It returns a Boolean value, which is false
if a portion of the directory could not be created.
bool EnsurePathExists(LPCTSTR lpszPath)
{
CString sPath;
if (DirectoryExists(lpszPath))
return true;
int nLen = _tcslen(lpszPath);
if (lpszPath[nLen - 1] == '\\')
nLen--;
int nCurrLen = 0;
if (nLen >= 3 && lpszPath[1] == ':' && lpszPath[2] == '\\')
nCurrLen = 2;
while (lpszPath[nCurrLen] == '\\')
nCurrLen++;
while (nCurrLen < nLen)
{
LPCTSTR psz = _tcschr(lpszPath + nCurrLen, '\\');
if (psz != NULL)
nCurrLen = (int)(psz - lpszPath);
else
nCurrLen = nLen;
sPath.SetString(lpszPath, nCurrLen);
if (!DirectoryExists(sPath))
if (!::CreateDirectory(sPath, NULL))
return false;
if (lpszPath[nCurrLen] != '\0')
nCurrLen++;
}
return true;
}
bool DirectoryExists(LPCTSTR lpszPath)
{
DWORD dw = ::GetFileAttributes(lpszPath);
return (dw != INVALID_FILE_ATTRIBUTES &&
(dw & FILE_ATTRIBUTE_DIRECTORY) != 0);
}
Listing 1: EnsurePathExists() function
The code processes a single component, or layer, of the path at a time, either ensuring it exists or creating it if it does not. It uses my helper routine DirectoryExists
to determine if each component exists. If it does not, that component is created using CreateDirectory
.
To save time, EnsurePathExists
starts by testing for the existence of the entire path. If it already exists, the function simply returns.
That's about all there is to it. Most of the details are just in making sure each component is properly parsed and tested. The code skips the root folder because you cannot create a root folder. The code also strips multiple leading backslashes, as might be seen in paths that refer to network locations.