自定义的常用文件与目录操作函数库,在win和linux平台做了跨平台的处理。(跨平台的处理可以作为参考比较。在win下目录的符号可以是\或者/,但是在linux下只能是/。)
下面给出的是源文件,实现接口函数的代码。每个接口函数都有很详细的功能说明。
/* 判断文件或目录是否存在* 在操作系统中,目录也是一个文件,如果要判断一个目录是否存在则应当使用DirectoryExists,
* 要判断一个文件是否存在且是一个归档文件则应当使用IsArchive。
* @如果文件或目录存在则返回true否则返回false
* %文件路径字符长度不得超过MAX_PATH
*/
bool FileUtil::FileExists(LPCTSTR sFilePath)
{
#if PLATFORM == WINDOWS32 || PLATFORM == WINDOWS64
DWORD dwAttr = GetFileAttributes(sFilePath);
if ( dwAttr == (DWORD)-1 )
return false;
else return true;
#endif
#if PLATFORM == LINUX32 || PLATFORM == LINUX64
struct stat file;
int res = stat(sFilePath, &file);
if(-1 != res && S_ISREG(file.st_mode))
{
return true;
}
else return false;
#endif
}
/* 判断文件是否存在且是一个可直接读取的归档文件(比如自定义的文本文件或者txt文件等)
* %文件路径字符长度不得超过MAX_PATH
*/
bool FileUtil::IsArchive(LPCTSTR sFilePath)
{
#if PLATFORM == WINDOWS32 || PLATFORM == WINDOWS64
DWORD dwAttr = GetFileAttributes(sFilePath);
if ( dwAttr == (DWORD)-1 || (dwAttr & FILE_ATTRIBUTE_ARCHIVE) == 0 )
return false;
else return true;
#endif
#if PLATFORM == LINUX32 || PLATFORM == LINUX64
//简单判断文件是否存在
struct stat file;
int res = stat(sFilePath, &file);
if(-1 != res && S_ISREG(file.st_mode))
{
return true;
}
else return false;
#endif
}
/* 判断目录是否存在,文件存在且文件是一个目录则返回true否则返回false
* %文件路径字符长度不得超过MAX_PATH
*/
bool FileUtil::IsDirectory(LPCTSTR sDirPath)
{
#if PLATFORM == WINDOWS32 || PLATFORM == WINDOWS64
DWORD dwAttr = GetFileAttributes(sDirPath);
if ( dwAttr == (DWORD)-1 || (dwAttr & FILE_ATTRIBUTE_DIRECTORY) == 0 )
return false;
else return true;
#endif
#if PLATFORM == LINUX32 || PLATFORM == LINUX64
struct stat file;
int res = stat(sDirPath, &file);
if(-1 != res && S_ISDIR(file.st_mode))
{
return true;
}
return false;
#endif
}
/* 获取文件或目录名称
* c:\abc\123.txt --> 123.txt
* c:\abc\efg\ --> efg
* 参数sDirBuf用于存储文件名称字符串
* 参数dwBufLen为sNameBuf参数的缓冲区字符(非字节)长度,其中含需要保留的终止字符,
如果dwBufLen值为0则函数不会将文件名拷贝到sNameBuf中;
如果dwBufLen值非0则函数会将文件名拷贝到sNameBuf中并会在sNameBuf中写入终止符;
如果缓冲区不够则只拷贝dwBufLen-1个字符并会在sNameBuf中写入终止符。
@函数返回拷贝文件名所需的字符长度(含终止符)
*/
SIZE_T FileUtil::ExtractFileName(LPCTSTR sFilePath, LPTSTR sNameBuf, SIZE_T dwBufLen)
{
LPCTSTR sNameStart, sNameEnd = sFilePath + _tcslen(sFilePath) - 1;
//跳过目录名称后连续的'/'或'\'
while ( sNameEnd >= sFilePath && (*sNameEnd == '/' || *sNameEnd == '\\') )
{
sNameEnd--;
}
sNameStart = sNameEnd;
sNameEnd++;
//定位目录名称起始的位置
while ( sNameStart >= sFilePath )
{
if ( *sNameStart == '/' || *sNameStart == '\\' )
break;
sNameStart--;
}
sNameStart++;
//拷贝目录名称
if ( sNameStart < sNameEnd )
{
SIZE_T dwNameLen = sNameEnd - sNameStart;
if ( dwBufLen > 0 )
{
if ( dwBufLen > dwNameLen )
dwBufLen = dwNameLen;
else dwBufLen--;
memcpy(sNameBuf, sNameStart, sizeof(*sNameStart) * dwBufLen);
sNameBuf[dwBufLen] = 0;
}
return dwNameLen;
}
return 0;
}
/* 获取文件路径中的文件名部分,不包含文件后缀部分
* c:\abc.txt --> abc
* 参数sNameBuf用于存储文件名称字符串
* 参数dwBufLen为sNameBuf参数的缓冲区字符(非字节)长度,其中含需要保留的终止字符,
如果dwBufLen值为0则函数不会将文件名拷贝到sNameBuf中;
如果dwBufLen值非0则函数会将文件名拷贝到sNameBuf中并会在sNameBuf中写入终止符;
如果缓冲区不够则只拷贝dwBufLen-1个字符并会在sNameBuf中写入终止符。
@函数返回拷贝文件名所需的字符长度(含终止符)
*/
SIZE_T FileUtil::ExtractFileNameOnly(LPCTSTR sFileName, LPTSTR sNameBuf, SIZE_T dwBufLen)
{
//文件名为空则直接返回0
if ( !*sFileName )
{
if ( dwBufLen > 0 )
sNameBuf[0] = 0;
return 0;
}
LPCTSTR sNameStart, sNameEnd = sFileName + _tcslen(sFileName) - 1;
//如果文件是目录
if ( *sNameEnd == '/' || *sNameEnd == '\\' )
{
//跳过目录名称后连续的'/'或'\'
while ( sNameEnd >= sFileName && (*sNameEnd == '/' || *sNameEnd == '\\') )
{
sNameEnd--;
}
sNameEnd++;
}
else
{
LPCTSTR sPtr = sNameEnd;
//找到文件后缀部分的起始位置
while ( sPtr >= sFileName )
{
if (*sPtr == '.')
{
sNameEnd = sPtr;
break;
}
if (*sPtr == '/' || *sPtr == '\\')
break;
}
}
sNameStart = sNameEnd - 1;
//定位目录名称起始的位置
while ( sNameStart >= sFileName )
{
if ( *sNameStart == '/' || *sNameStart == '\\' )
break;
sNameStart--;
}
sNameStart++;
//拷贝目录名称
if ( sNameStart < sNameEnd )
{
SIZE_T dwNameLen = sNameEnd - sNameStart;
if ( dwBufLen > 0 )
{
if ( dwBufLen > dwNameLen )
dwBufLen = dwNameLen;
else dwBufLen--;
memcpy(sNameBuf, sNameStart, sizeof(*sNameStart) * dwBufLen);
sNameBuf[dwBufLen] = 0;
}
return dwNameLen;
}
return 0;
}
/* 获取文件名或文件路径中的文件后缀部分
* abc.txt --> .txt
* 返回值包含后缀符号'.'
*/
LPCTSTR FileUtil::ExtractFileExt(LPCTSTR sFileName)
{
LPCTSTR sResult = NULL;
while (*sFileName)
{
if (*sFileName == '.')
sResult = sFileName;
sFileName++;
}
return sResult;
}
/* 获取文件所在目录路径
* c:\abc\efg\123.txt --> c:\abc\efg\
* c:\abc\efg\ --> c:\abc\
* 参数sDirBuf用于存储目录字符串
* 参数dwBufLen为sDirName参数的缓冲区字符(非字节)长度,其中含需要保留的终止字符,
如果dwBufLen值为0则函数不会将目录路径拷贝到sDirBuf中;
如果dwBufLen值非0则函数会将目录路径拷贝到sDirBuf中并会在sDirBuf中写入终止符;
如果缓冲区不够则只拷贝dwBufLen-1个字符并会在sDirBuf中写入终止符。
@函数返回拷贝目录路径所需的字符长度(含终止符)
*/
SIZE_T FileUtil::ExtractFileDirectory(LPCTSTR sFilePath, LPTSTR sDirBuf, SIZE_T dwBufLen)
{
LPCTSTR sDirEnd = sFilePath + _tcslen(sFilePath) - 1;
while (sDirEnd >= sFilePath && *sDirEnd != '/' && *sDirEnd != '\\')
{
sDirEnd--;
}
if ( sDirEnd > sFilePath )
{
SIZE_T dwNameLen = sDirEnd - sFilePath;
if ( dwBufLen > 0 )
{
if ( dwBufLen > dwNameLen )
dwBufLen = dwNameLen;
else dwBufLen--;
memcpy(sDirBuf, sFilePath, sizeof(*sDirBuf) * dwBufLen);
sDirBuf[dwBufLen] = 0;
}
return dwNameLen;
}
return 0;
}
/* 获取顶层目录名称
* (abc\efg\ --> abc)
* 参数ppChildDirPath用于存顶层目录之后的目录路径,参数可以为空
* 参数sDirName用于存储目录字符串
* 参数dwBufLen为sDirName参数的缓冲区字符(非字节)长度,其中含需要保留的终止字符,
如果dwBufLen值为0则函数不会将目录名拷贝到sDirName中;
如果dwBufLen值非0则函数会将目录名拷贝到sDirName中并会在sDirName中写入终止符;
如果缓冲区不够则只拷贝dwBufLen-1个字符并会在sDirName中写入终止符。
@函数返回拷贝目录名所需的字符长度(含终止符)
*/
SIZE_T FileUtil::ExtractTopDirectoryName(LPCTSTR sDirPath, OUT LPCTSTR *ppChildDirPath, LPTSTR sDirName, SIZE_T dwBufLen)
{
LPCTSTR sNameEnd;
//跳过目录名称前连续的'/'或'\'
while ( *sDirPath && (*sDirPath == '/' || *sDirPath == '\\') )
{
sDirPath++;
}
sNameEnd = sDirPath;
//定位目录名称起始的位置
while ( *sNameEnd )
{
if ( *sNameEnd == '/' || *sNameEnd == '\\' )
break;
sNameEnd++;
}
//拷贝目录名称
if ( sNameEnd > sDirPath )
{
SIZE_T dwNameLen = sNameEnd - sDirPath;
if ( dwBufLen > 0 )
{
if ( dwBufLen > dwNameLen )
dwBufLen = dwNameLen;
else dwBufLen--;
memcpy(sDirName, sDirPath, sizeof(*sDirPath) * dwBufLen);
sDirName[dwBufLen] = 0;
if (ppChildDirPath)
*ppChildDirPath = sNameEnd;
}
return dwNameLen;
}
return 0;
}
/* 逐层创建目录
* 如果创建目录C:\a\b\c\d,最终目录的父目录不存在则逐级创建父目录并创建最终目录
* @如果目录完全创建成功则函数返回true,否则返回false。
* %如果在创建某个父目录成功后并创建子目录失败,则函数返回false且已经创建的父目录不会被删除。
* %目录路径的总体字符长度,函数要求必须在MAX_PATH个字符长度以内
*/
bool FileUtil::DeepCreateDirectory(LPCTSTR sDirPath)
{
TCHAR sPath[4096];
LPTSTR sPathPtr = sPath;
SIZE_T dwNameLen, dwBufLen = ArrayCount(sPath) - 1;
DWORD dwAttr;
while (true)
{
dwNameLen = ExtractTopDirectoryName(sDirPath, &sDirPath, sPathPtr, dwBufLen);//获取顶层目录名称* (abc\efg\ --> abc)
//如果目录名称长度超过目录缓冲区长度则放弃
if ( dwNameLen >= dwBufLen )
return false;
//如果目录名称长度为0则表示所有目录均已创建完成
if (dwNameLen == 0)
return true;
sPathPtr += dwNameLen;
#if PLATFORM == WINDOWS32 || PLATFORM == WINDOWS64
//如果目录名称不是驱动器名称则检查和创建目录
if (sPathPtr[-1] != ':')
{
//如果目录不存在则创建此目录
dwAttr = GetFileAttributes(sPath);
if ( (dwAttr == (DWORD)-1 && GetLastError() == ERROR_FILE_NOT_FOUND) )
{
if (!CreateDirectory(sPath, NULL))
return false;
}
//如果文件存在且文件不是目录则返回false
else if ( !(dwAttr & FILE_ATTRIBUTE_DIRECTORY) )
{
return false;
}
}
#endif
#if PLATFORM == LINUX32 || PLATFORM == LINUX64
struct stat fileStat;
if(-1 == stat(sPath, &fileStat))//没有该文件或目录
{
if(ENOENT == errno)//错误码是 ENOENT: No such file or directory
{
if(-1 == mkdir(sPath, S_IRWXG))//创建一层目录
{
return false;
}
}
}
#endif
sPathPtr[0] = '/';
sPathPtr++;
if ( dwBufLen > dwNameLen )
dwBufLen -= dwNameLen + 1;
else dwBufLen = 0;
}
return false;
}
其中的一些自定义的宏定义和类型定义如下:
由于跨平台的原因的自定义宏(使用时,没有跨平台需要的话,可删除不需要的部分)
#define _tcslen(STR) strlen(STR)
typedef const char *LPCTSTR, *LPCSTR;
typedef size_t SIZE_T;
其他的宏
获取数组长度
#define ArrayCount(a)(sizeof(a)/sizeof((a)[0]))