11/25/2007

Check File Existence on Windows Platform

There are several ways to accomplish this:

1. Use _access() in CRT.
#include <io.h>
if
( _access(filename, 0) == 0 )
{
  
// file exists
}
2. Use GetFileAttributes() in Win32 or stat() in POSIX(Win32 has _stat()).
if (INVALID_FILE_ATTRIBUTES != GetFileAttributes(fileName))
{
   // file exists
}

3. Just create it and check the returned error code, using CreateDirectory() or CreateFile() in Win32.
HANDLE hFile = NULL;
hFile = CreateFile(fileName, 0, 0, NULL, CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE, NULL);
if ( hFile == INVALID_HANDLE_VALUE)
{
  if (GetLastError() == ERROR_ALREADY_EXISTS)
  {
    // file exists
  }
}
else
{
  CloseHandle(hFile);
}

4. Use FindFirstFile() in Win32.
WIN32_FIND_DATA wfd;
HANDLE hFind = FindFirstFile(fileName, &wfd);
if (hFind != INVALID_HANDLE_VALUE)
{
  CloseHandle(hFind);
  // file exists
}

5. Use other C++ file stream/file system library
  5.1 try open() on fstream in STL, if not exists, it will fail.
  5.2 try Boost library: boost::filesystem::exists(fileName)

But be careful about the atomic semantic and race condition. If you want to check the file's existence and then do some operation with that file(such as open for read/write), solution NO.3 is best for you.

11/20/2007

Create Mutiple Level Directories

1. SHCreateDirectoryEx()
  This function is included in Windows Shell and Control component: header is shlobj.h, library is shell32.lib and DLL is shell32.dll.
  It will create all intermediate directories in the path parameter. Both ANSI and UNICODE version path characters are supported.

2. MakeSureDirectoryPathExists()
  This function is included in Windows DbgHelp component: header is Dbghelp.h, Library is Dbghelp.lib, DLL is Dbghelp.dll.
  It will create all directories from the root, but just provide ANSI version, no UNICODE version.

3. Use CreateDirectory() to build your own one(recursively or iteratively).
  The following code has the same semantic as CreateDirectoryW().(Same return value and same GetLastError() value)
 1 BOOL CreateFullPathDirectoryW(const wchar_t * dirPath,
 2     LPSECURITY_ATTRIBUTES secAttr)
 3 {
 4     std::wstring curDir(dirPath);
 5     while(curDir.at(curDir.length() - 1) == L'\\')
 6     {
 7         curDir.erase(curDir.length() - 1, curDir.length());
 8     }
 9
10     if (!CreateDirectoryW(curDir.c_str(), secAttr))
11     {
12         DWORD dwErr = GetLastError();
13         if (ERROR_PATH_NOT_FOUND == dwErr)
14         {
15             std::wstring parentDir = curDir.substr(0, curDir.rfind(L'\\'));
16             if (parentDir.length() == 0)
17             // one level dir
18             {
19                 SetLastError(dwErr);
20                 return FALSE;
21             }
22
23             if (CreateFullPathDirectoryW(parentDir.c_str(), secAttr))
24             // create parent OK
25             {
26                 return CreateDirectoryW(dirPath, secAttr);
27             }
28             else
29             // we have correct Win32 LastError here
30             {
31                 return FALSE;
32             }
33         }
34         else
35         // already exists or other error
36         {
37             SetLastError(dwErr);
38             return FALSE;
39         }
40     }
41
42     return TRUE;
43 }
44