递归创建文件和文件夹
WIndows API函数CreateFile和CreateDirectory用于创建文件和目录,但设想这样一种情况:需要创建文件C:\test\test.txt,但是C:\test\目录不存在,简单地调用CreateFile不会成功了,创建目录也是一样。
我在Windows API找了很久,没找到能满足要求的函数,Shell API里也没有,于是只能靠自己实现了。
传入目录时,有些人习惯于在尾部加反斜杠,有些又没加反斜杠,为了方便编程,先封装一个方法来规范一下:
//若bAddSpec 为真,则确保szDst路径末尾带有"\", 若bAddSpec为假,则去除lpszPath末尾的"\"或"/"
template<size_t nSize>
inline void ModifyPathSpec( TCHAR (&szDst)[nSize], BOOL bAddSpec )
{
int nLen = lstrlen( szDst );
ASSERT( nLen > 0 );
TCHAR ch = szDst[ nLen - 1 ];
if( ( ch == _T('\\') ) || ( ch == _T('/') ) )
{
if( !bAddSpec )
{
szDst[ nLen - 1 ] = _T('\0');
}
}
else
{
if( bAddSpec )
{
szDst[ nLen ] = _T('\\');
szDst[ nLen + 1 ] = _T('\0');
}
}
}
template<size_t nSize>
inline void ModifyPathSpec( TCHAR (&szDst)[nSize], BOOL bAddSpec )
{
int nLen = lstrlen( szDst );
ASSERT( nLen > 0 );
TCHAR ch = szDst[ nLen - 1 ];
if( ( ch == _T('\\') ) || ( ch == _T('/') ) )
{
if( !bAddSpec )
{
szDst[ nLen - 1 ] = _T('\0');
}
}
else
{
if( bAddSpec )
{
szDst[ nLen ] = _T('\\');
szDst[ nLen + 1 ] = _T('\0');
}
}
}
首先讨论创建文件夹的情况,创建文件夹时主要是个递归过程,首先判断上级目录是否存在,
如果不存在,则递归创建上级目录.代码如下:
//嵌套创建文件夹
inline BOOL CreateDirectoryNested( LPCTSTR lpszDir )
{
if( ::PathIsDirectory( lpszDir ) ) return TRUE;
TCHAR szPreDir[ MAX_PATH ];
_tcscpy_s( szPreDir, lpszDir );
//确保路径末尾没有反斜杠
ModifyPathSpec( szPreDir, FALSE );
//获取上级目录
BOOL bGetPreDir = ::PathRemoveFileSpec( szPreDir );
if( !bGetPreDir ) return FALSE;
//如果上级目录不存在,则递归创建上级目录
if( !::PathIsDirectory( szPreDir ) )
{
CreateDirectoryNested( szPreDir );
}
return ::CreateDirectory( lpszDir, NULL );
}
创建文件目录后,直接调用CreateFile就可以创建文件了.代码如下:
inline BOOL CreateDirectoryNested( LPCTSTR lpszDir )
{
if( ::PathIsDirectory( lpszDir ) ) return TRUE;
TCHAR szPreDir[ MAX_PATH ];
_tcscpy_s( szPreDir, lpszDir );
//确保路径末尾没有反斜杠
ModifyPathSpec( szPreDir, FALSE );
//获取上级目录
BOOL bGetPreDir = ::PathRemoveFileSpec( szPreDir );
if( !bGetPreDir ) return FALSE;
//如果上级目录不存在,则递归创建上级目录
if( !::PathIsDirectory( szPreDir ) )
{
CreateDirectoryNested( szPreDir );
}
return ::CreateDirectory( lpszDir, NULL );
}
//嵌套创建文件,bOverride为TRUE表示覆盖原已存在的文件
inline BOOL CreateFileNested( LPCTSTR lpszFile, BOOL bOverride = TRUE )
{
if( ::PathFileExists( lpszFile ) )return TRUE;
TCHAR szDir[ MAX_PATH ];
_tcscpy_s( szDir, lpszFile );
//获取文件目录
BOOL bGetDir = ::PathRemoveFileSpec( szDir );
if( !bGetDir )return FALSE;
//创建文件目录
if( !CreateDirectoryNested( szDir ) )return FALSE;
DWORD dwCreate = bOverride?CREATE_ALWAYS:OPEN_ALWAYS;
HANDLE hFile = ::CreateFile( lpszFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
dwCreate, FILE_FLAG_BACKUP_SEMANTICS, NULL );
if( hFile == INVALID_HANDLE_VALUE)
return FALSE;
::CloseHandle( hFile );
return TRUE;
}
inline BOOL CreateFileNested( LPCTSTR lpszFile, BOOL bOverride = TRUE )
{
if( ::PathFileExists( lpszFile ) )return TRUE;
TCHAR szDir[ MAX_PATH ];
_tcscpy_s( szDir, lpszFile );
//获取文件目录
BOOL bGetDir = ::PathRemoveFileSpec( szDir );
if( !bGetDir )return FALSE;
//创建文件目录
if( !CreateDirectoryNested( szDir ) )return FALSE;
DWORD dwCreate = bOverride?CREATE_ALWAYS:OPEN_ALWAYS;
HANDLE hFile = ::CreateFile( lpszFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
dwCreate, FILE_FLAG_BACKUP_SEMANTICS, NULL );
if( hFile == INVALID_HANDLE_VALUE)
return FALSE;
::CloseHandle( hFile );
return TRUE;
}