C语言:如何得到指定地址的文件夹中所有文件的文件名和其修改时间 包括子文件内的
windows下 展开
俺前段时间写了段功能相似的程序,但用的是用C++/STL写的,访问目录使用了win32 api(能访问指定目录的子目录)。
获取文件名与修改时间由FileOfDirectory::detectFiles实现(其实你只需要看这一个函数即可)。
这段程序以STL数组保存单个文件名,查询过程中没有回溯,wcsstr函数内部也是KMP,所以事实上这个程序也是按KMP查询的
安时间排序时使用STL算法库,时间复杂度同快速排序。
最后,这段代码是在VS2010编译的。
# include <vector>
# include <algorithm>
struct FileNameAndTime
{
wchar_t szPath[MAX_PATH]; //file directory
wchar_t szName[MAX_PATH]; //file name
FILETIME lastAcc; //last access time
FileNameAndTime()
{
memset(&lastAcc, 0, sizeof(lastAcc));
memset(szName, 0, sizeof(wchar_t) * MAX_PATH);
memset(szPath, 0, sizeof(wchar_t) * MAX_PATH);
}
FileNameAndTime(const PWCHAR fn, const PWCHAR pa, const LPFILETIME ft)
{
if( (0 == fn) || (0 == pa) || (0 == ft) )
return;
memcpy(&lastAcc, ft, sizeof(lastAcc));
wcscpy(szName, fn);
wcscpy(szPath, pa);
}
FileNameAndTime(const FileNameAndTime& fnd)
{
memcpy(&this->lastAcc, &fnd.lastAcc, sizeof(this->lastAcc));
wcscpy(this->szName, fnd.szName);
wcscpy(this->szPath, fnd.szPath);
}
const FileNameAndTime& operator=(const FileNameAndTime& fnd)
{
if(this != &fnd) {
memcpy(&this->lastAcc, &fnd.lastAcc, sizeof(this->lastAcc));
wcscpy(this->szName, fnd.szName);
wcscpy(this->szPath, fnd.szPath);
}
return *this;
}
void GetFullPath( wchar_t (&fp)[MAX_PATH] ) const
{
wcscpy(fp, szPath);
wcscat(fp, szName);
}
friend bool operator>(const FileNameAndTime& l, const FileNameAndTime& r); //compare this object by access time
};
bool operator<(const FileNameAndTime& l, const FileNameAndTime& r) //for sort
{
if(l.lastAcc.dwHighDateTime < r.lastAcc.dwHighDateTime)
return true;
else if (l.lastAcc.dwHighDateTime == r.lastAcc.dwHighDateTime)
{
if(l.lastAcc.dwLowDateTime < r.lastAcc.dwLowDateTime)
return true;
}
return false;
}
class FileOfDirectory
{
private:
static const wchar_t szDot[];
static const wchar_t szDotDot[];
static const wchar_t cStar;
static const wchar_t cSlash;
private:
std::vector<FileNameAndTime> vecFT;
wchar_t szCurrentPath[MAX_PATH];
private:
void validatePath(const wchar_t* pPath)
{
wcscpy(szCurrentPath, pPath);
int len = wcslen(szCurrentPath);
if( (cStar != szCurrentPath[len - 1])
&& (cSlash != szCurrentPath[len - 2]) )
{
szCurrentPath[len] = cSlash;
szCurrentPath[len + 1] = cStar;
szCurrentPath[len + 2] = 0;
return;
}
if( (cStar != szCurrentPath[len - 1])
&& (cSlash == szCurrentPath[len - 2]) )
{
szCurrentPath[len] = cStar;
szCurrentPath[len + 1] = 0;
return;
}
}
void detectFiles(const LPWSTR szDir)
{
WIN32_FIND_DATA ffd;
HANDLE hFind = ::FindFirstFile(szDir, &ffd);
if (INVALID_HANDLE_VALUE == hFind)
return ;
do
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if( (0 == wcscmp(ffd.cFileName, szDot)) || (0 == wcscmp(ffd.cFileName, szDotDot)))
continue;
else
{
wchar_t szTempPath[MAX_PATH];
wcscpy(szTempPath, szDir);
szTempPath[wcslen(szTempPath) - 1] = 0;
wcscat(szTempPath, ffd.cFileName);
int len = wcslen(szTempPath);
szTempPath[len] = cSlash;
szTempPath[len + 1] = cStar;
szTempPath[len + 2] = 0;
detectFiles(szTempPath);
}
}
else {
wchar_t path[MAX_PATH];
wcscpy(path, szDir);
path[wcslen(path) - 1] = 0;
vecFT.push_back(FileNameAndTime(ffd.cFileName,path, &ffd.ftLastAccessTime));
}
}
while (::FindNextFile(hFind, &ffd) != 0);
}
public:
FileOfDirectory(const LPWSTR szDir)
{
validatePath(szDir);
detectFiles(szCurrentPath);
}
void SortByAccessTime()
{
sort(vecFT.begin(), vecFT.end());
}
int NumOfFiles() const { return vecFT.size(); }
int FindFilesByKeyWord(wchar_t* pszFn, int* outCome, int outComeLen, bool bMatchAll = false)
{
wchar_t szTemp[MAX_PATH], szFnLwr[MAX_PATH];
int index = 0;
wcscpy(szFnLwr, pszFn);
_wcslwr(szFnLwr);
for(int i = 0; i < vecFT.size(); ++i)
{
wcscpy(szTemp, vecFT[i].szName);
_wcslwr(szTemp);
if(true == bMatchAll)
{
if(0 == wcscmp(szTemp, szFnLwr))
{
if(index >= outComeLen)
return index;
outCome[index++] = i;
}
}
else
{
if(0 != wcsstr(szTemp, szFnLwr))
{
if(index >= outComeLen)
return index;
outCome[index++] = i;
}
}
}
}
FileNameAndTime GetItemByID(int index)
{
if( (index >= 0) && (index < vecFT.size()) )
return FileNameAndTime(vecFT[index]);
}
};
const wchar_t FileOfDirectory::szDot[] = L".";
const wchar_t FileOfDirectory::szDotDot[] = L"..";
const wchar_t FileOfDirectory::cStar = L'*';
const wchar_t FileOfDirectory::cSlash = L'\\';
void __stdcall entp3() //测试程序
{
FileOfDirectory fod(L"E:\\game");
int ids[256] = { 0 };
fod.SortByAccessTime();
int len = fod.FindFilesByKeyWord(L"main", ids, 256);
for(int i = 0; i <len; ++i) {
FileNameAndTime fnt(fod.GetItemByID(ids[i]));
CDbgString::OutputDbgStringW(L"\r\n%s%s", fnt.szPath, fnt.szName);
}
}
测试结果如图所示。
我在vs2010下编译不了 为什么没有main主函数 还看不太懂class FileOfDirectory
哦,俺也用的是vs2010,这个要设置一下才能不写main。
项目名-右键-属性-链接器-子系统:改为未设置
项目名-右键-属性-链接器-高级:输入entp3就能通过编译。
你也可以不改项目属性。
如果你写控制台程序,把entp3的代码写到main里即可,如果是windows程序,写到WinMain里即可。
当然你可以在自己的main函数中用FileOfDirectory类。
FileOfDirectory中:
validatePath用于修改路径的,比如你想枚举出c:\abc下所有的文件与文件夹,函数FindFirstFile要求你输入c:\abc\*才行。
detectFiles是得到目录下所有文件的,通过递归扫描子目录。
SortByAccessTime是按修改时间排序文件的,因为先搜索近期用过的文件意义比较大。
int FindFilesByKeyWord(wchar_t* pszFn, int* outCome, int outComeLen, bool bMatchAll = false)用于搜索指定文件,可以返回所有符合条件的文件名索引。pszFn是关键字,数组outCome用于存放搜索到的文件的索引,outComeLen是数组outCome的长度,bMatchAll = true表示必须和关键字全部匹配才能返回,反之只要文件名中包含关键就可返回。
GetItemByID更具索引返回FileNameAndTime 对象,一般和FindFilesByKeyWord配合使用。
char** getFileNameArray(const char *path, int* fileCount)
{
int count = 0;
char **fileNameList = NULL;
struct dirent* ent = NULL;
DIR *pDir;
char dir[512];
struct stat statbuf;
//打开目录
if ((pDir = opendir(path)) == NULL)
{
myLog("Cannot open directory:%s\n", path);
return NULL;
}
//读取目录
while ((ent = readdir(pDir)) != NULL)
{ //统计当前文件夹下有多少文件(不包括文件夹)
//得到读取文件的绝对路径名
snprintf(dir, 512, "%s/%s", path, ent->d_name);
//得到文件信息
lstat(dir, &statbuf);
//判断是目录还是文件
if (!S_ISDIR(statbuf.st_mode))
{
count++;
}
} //while
//关闭目录
closedir(pDir);
// myLog("共%d个文件\n", count);
//开辟字符指针数组,用于下一步的开辟容纳文件名字符串的空间
if ((fileNameList = (char**) myMalloc(sizeof(char*) * count)) == NULL)
{
myLog("Malloc heap failed!\n");
return NULL;
}
//打开目录
if ((pDir = opendir(path)) == NULL)
{
myLog("Cannot open directory:%s\n", path);
return NULL;
}
//读取目录
int i;
for (i = 0; (ent = readdir(pDir)) != NULL && i < count;)
{
if (strlen(ent->d_name) <= 0)
{
continue;
}
//得到读取文件的绝对路径名
snprintf(dir, 512, "%s/%s", path, ent->d_name);
//得到文件信息
lstat(dir, &statbuf);
//判断是目录还是文件
if (!S_ISDIR(statbuf.st_mode))
{
if ((fileNameList[i] = (char*) myMalloc(strlen(ent->d_name) + 1))
== NULL)
{
myLog("Malloc heap failed!\n");
return NULL;
}
memset(fileNameList[i], 0, strlen(ent->d_name) + 1);
strcpy(fileNameList[i], ent->d_name);
myLog("第%d个文件:%s\n", i, ent->d_name);
i++;
}
} //for
//关闭目录
closedir(pDir);
*fileCount = count;
return fileNameList;
}
windows下