判断一个文件和目录是否存在,可以使用_access或者_stat函数,但是要注意两点:
- _access能检测给定路径是否存在,但是无法区分这个路径是文件路径还是目录路径。比如指定路径d:\123,如果D盘下存在文件名为123的文件或者目录名为123的目录,_access返回信息都是存在的,但是无法区分这个路径是文件路径还是目录路径。_stat函数则能正确区分文件还是目录。
- 路径末尾是否能带有反斜杠“\”对于检测的结果也是不一样的:
末尾是否能有"\" 盘符 目录 文件 本地 网络 本地 网络 UNC 本地 网络 UNC _access 无影响 无影响 无影响 无影响 无影响 不能有"\" 无影响 无影响 _stat 必须有"\" 必须有"\" 不能有"\" 不能有"\" 不能有"\" 不能有"\" 不能有"\" 不能有"\"
以下是我写的测试程序来进行测试和结果,d:\123和t:\123是文件,d:\456和t:\456是目录,t盘是映射的\\172.16.254.101\d$\Lilong\tapefile\共享盘:
#include <cstdio>
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <Windows.h>
void Test(char strPath[])
{
printf("%s\n", strPath);
int nRet = _access(strPath, 0);
int nErrNo = errno;
printf("_access:nRet = %d, nErrNo = %d, LastErr = %d\n", nRet, nErrNo, GetLastError());
struct _stat buf = {0};
nRet = _stat(strPath, &buf);
nErrNo = errno;
printf("_stat:nRet = %d, nErrNo = %d, LastErr = %d, _S_IFDIR=%x, _S_IFREG=%x\n\n",
nRet, nErrNo, GetLastError(), buf.st_mode & _S_IFDIR, buf.st_mode & _S_IFREG);
}
int main(int argc, char* argv[])
{
Test("");
Test("d");
Test("d:");
Test("d:\\");
Test("d:\\\\");
Test("d:\\123");
Test("d:\\123\\");
Test("d:\\123\\\\");
Test("d:\\456");
Test("d:\\456\\");
Test("d:\\456\\\\");
Test("t");
Test("t:");
Test("t:\\");
Test("t:\\123");
Test("t:\\123\\");
Test("t:\\456");
Test("t:\\456\\");
Test("\\\\172.16.254.101\\d$\\Lilong\\tapefile");
Test("\\\\172.16.254.101\\d$\\Lilong\\tapefile\\");
Test("\\\\172.16.254.101\\d$\\Lilong\\tapefile\\123");
Test("\\\\172.16.254.101\\d$\\Lilong\\tapefile\\123\\");
Test("\\\\172.16.254.101\\d$\\Lilong\\tapefile\\456");
Test("\\\\172.16.254.101\\d$\\Lilong\\tapefile\\456\\");
return 0;
}
_access:nRet = -1, nErrNo = 2, LastErr = 3
_stat:nRet = -1, nErrNo = 2, LastErr = 3, _S_IFDIR=0, _S_IFREG=0
d
_access:nRet = -1, nErrNo = 2, LastErr = 2
_stat:nRet = -1, nErrNo = 2, LastErr = 2, _S_IFDIR=0, _S_IFREG=0
d:
_access:nRet = 0, nErrNo = 2, LastErr = 2
_stat:nRet = -1, nErrNo = 2, LastErr = 2, _S_IFDIR=0, _S_IFREG=0
d:\
_access:nRet = 0, nErrNo = 2, LastErr = 2
_stat:nRet = 0, nErrNo = 2, LastErr = 0, _S_IFDIR=4000, _S_IFREG=0
d:\\
_access:nRet = 0, nErrNo = 2, LastErr = 0
_stat:nRet = 0, nErrNo = 2, LastErr = 2, _S_IFDIR=4000, _S_IFREG=0
d:\123
_access:nRet = 0, nErrNo = 2, LastErr = 2
_stat:nRet = 0, nErrNo = 2, LastErr = 2, _S_IFDIR=0, _S_IFREG=8000
d:\123\
_access:nRet = -1, nErrNo = 22, LastErr = 123
_stat:nRet = -1, nErrNo = 2, LastErr = 267, _S_IFDIR=0, _S_IFREG=0
d:\123\\
_access:nRet = -1, nErrNo = 22, LastErr = 123
_stat:nRet = -1, nErrNo = 2, LastErr = 267, _S_IFDIR=0, _S_IFREG=0
d:\456
_access:nRet = 0, nErrNo = 2, LastErr = 267
_stat:nRet = 0, nErrNo = 2, LastErr = 267, _S_IFDIR=4000, _S_IFREG=0
d:\456\
_access:nRet = 0, nErrNo = 2, LastErr = 267
_stat:nRet = -1, nErrNo = 2, LastErr = 2, _S_IFDIR=0, _S_IFREG=0
d:\456\\
_access:nRet = 0, nErrNo = 2, LastErr = 2
_stat:nRet = -1, nErrNo = 2, LastErr = 2, _S_IFDIR=0, _S_IFREG=0
t
_access:nRet = -1, nErrNo = 2, LastErr = 2
_stat:nRet = -1, nErrNo = 2, LastErr = 2, _S_IFDIR=0, _S_IFREG=0
t:
_access:nRet = 0, nErrNo = 2, LastErr = 2
_stat:nRet = -1, nErrNo = 2, LastErr = 2, _S_IFDIR=0, _S_IFREG=0
t:\
_access:nRet = 0, nErrNo = 2, LastErr = 2
_stat:nRet = 0, nErrNo = 2, LastErr = 2, _S_IFDIR=4000, _S_IFREG=0
t:\123
_access:nRet = 0, nErrNo = 2, LastErr = 2
_stat:nRet = 0, nErrNo = 2, LastErr = 2, _S_IFDIR=0, _S_IFREG=8000
t:\123\
_access:nRet = 0, nErrNo = 2, LastErr = 2
_stat:nRet = -1, nErrNo = 2, LastErr = 267, _S_IFDIR=0, _S_IFREG=0
t:\456
_access:nRet = 0, nErrNo = 2, LastErr = 267
_stat:nRet = 0, nErrNo = 2, LastErr = 267, _S_IFDIR=4000, _S_IFREG=0
t:\456\
_access:nRet = 0, nErrNo = 2, LastErr = 267
_stat:nRet = -1, nErrNo = 2, LastErr = 2, _S_IFDIR=0, _S_IFREG=0
\\172.16.254.101\d$\Lilong\tapefile
_access:nRet = 0, nErrNo = 2, LastErr = 2
_stat:nRet = 0, nErrNo = 2, LastErr = 2, _S_IFDIR=4000, _S_IFREG=0
\\172.16.254.101\d$\Lilong\tapefile\
_access:nRet = 0, nErrNo = 2, LastErr = 2
_stat:nRet = -1, nErrNo = 2, LastErr = 2, _S_IFDIR=0, _S_IFREG=0
\\172.16.254.101\d$\Lilong\tapefile\123
_access:nRet = 0, nErrNo = 2, LastErr = 2
_stat:nRet = 0, nErrNo = 2, LastErr = 2, _S_IFDIR=0, _S_IFREG=8000
\\172.16.254.101\d$\Lilong\tapefile\123\
_access:nRet = 0, nErrNo = 2, LastErr = 2
_stat:nRet = -1, nErrNo = 2, LastErr = 267, _S_IFDIR=0, _S_IFREG=0
\\172.16.254.101\d$\Lilong\tapefile\456
_access:nRet = 0, nErrNo = 2, LastErr = 267
_stat:nRet = 0, nErrNo = 2, LastErr = 267, _S_IFDIR=4000, _S_IFREG=0
\\172.16.254.101\d$\Lilong\tapefile\456\
_access:nRet = 0, nErrNo = 2, LastErr = 267
_stat:nRet = -1, nErrNo = 2, LastErr = 2, _S_IFDIR=0, _S_IFREG=0
为了更好的检测文件还是目录路径是否存在,我写了以下函数,能针对文件还是目录进行检测:
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
// 返回值:
// 0:成功,指定的文件或目录路径存在
// ENOENT(2):指定的文件或目录路径不存在
// EINVAL(22):参数非法
// ENODEV(19):指定的路径存在,但是类型与指定的类型不一致
// 其他:其他错误
int IsPathExist(const CString strPathName, BOOL bCheckFilePath = TRUE)
{
CString strPathTmp(strPathName);
strPathTmp.Replace(_T("/"), _T("\\"));
strPathTmp.TrimRight(_T("\\"));
if (1 == strPathTmp.GetLength()) // 驱动器盘符
{
strPathTmp += _T(":\\");
}
else if (2 == strPathTmp.GetLength() && strPathTmp.Right(1) == _T(":"))
{
strPathTmp += _T("\\");
}
struct _stat stPath = {0};
int nRet = _tstat(strPathTmp, &stPath);
do
{
if (0 != nRet)
{
nRet = errno;
break ;
}
BOOL IsFilePath = (_S_IFREG == (_S_IFREG & stPath.st_mode));
BOOL IsDirPath = (_S_IFDIR == (_S_IFDIR & stPath.st_mode));
if ((bCheckFilePath && !IsFilePath)
|| (!bCheckFilePath && !IsDirPath))
{
nRet = ENODEV;
}
} while (FALSE);
return nRet;
}