遍历一个磁盘下的全部文件

kellen_1 2015-07-23 08:55:47
用FindFirstFile 和 FindNextFile 这两个函数去遍历一个磁盘下的全部文件,结果是有的文件目录下的文件遍历出来了,有的文件目录只遍历了一部分,还有的返回 无效文件句柄,真的好纠结啊!!求大神帮我看一下修改下代码


#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
#include "string.h"

void TraverseFile(char* path)
{
WIN32_FIND_DATA wfd = {0};
char szText[256] = {0};
sprintf(szText,"%s/*.*",path);
HANDLE hFind = FindFirstFile(szText,&wfd);
if(hFind == INVALID_HANDLE_VALUE)
{
printf ("Invalid file handle. Error is %u \n", GetLastError());
return ;
}
if(wfd.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY)
{
printf("%s\n",wfd.cFileName);
}
else if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
&& strcmp(wfd.cFileName,".") != 0
&& strcmp(wfd.cFileName,".") != 0)
{
printf("[%s]\n",wfd.cFileName);
char szTextr[256] = {0};
strcat(szTextr,path);
sprintf(szTextr,"/%s",wfd.cFileName);
TraverseFile(szTextr);
}
while(FindNextFile(hFind,&wfd))
{
if (wfd.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY)
{
printf ("%s\n", wfd.cFileName);
}
else if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
&& strcmp(wfd.cFileName, ".") != 0
&& strcmp(wfd.cFileName, "..") != 0)
{
printf("[%s]\n",wfd.cFileName);
char szTexts[256] = {0};
strcat(szTexts,path);
sprintf(szTexts,"/%s",wfd.cFileName);
TraverseFile(szTexts);
}
}
}


int main(int argc, char* argv[])
{
TraverseFile("G:");
return 0;
}

...全文
172 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2015-07-24
  • 打赏
  • 举报
回复
引用 5 楼 pb830 的回复:
[quote=引用 3 楼 zhao4zhong1 的回复:] system("dir /b /a-d /s c:\\*.* >d:\\allfilesinsub.txt"); //读文件d:\\allfilesinsub.txt的内容即C:\\下所有文件的名字包含子目录 请记住,能用shell命令获取文件、文件夹信息或者操作文件、文件夹最好用shell命令获取或者操作,而不要用各种API获取或者操作,因为当遇到非法文件夹名或非法文件名或非法文件长度、非法文件日期、压缩文件、链接文件、稀疏文件……等各种意料之外的情况时,API会处理的不全面或陷入死循环,而shell命令不会。
那例如boost::filesystem这种库呢,用这种东西好还是shell好?[/quote] 你自己两种都用于至少有两百万个文件的硬盘上试试看不就知道了。 不要迷信书、考题、老师、回帖; 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实! 有人说一套做一套,你相信他说的还是相信他做的? 其实严格来说这个世界上古往今来所有人都是说一套做一套,不是吗?
  • 打赏
  • 举报
回复
引用 3 楼 zhao4zhong1 的回复:
system("dir /b /a-d /s c:\\*.* >d:\\allfilesinsub.txt"); //读文件d:\\allfilesinsub.txt的内容即C:\\下所有文件的名字包含子目录 请记住,能用shell命令获取文件、文件夹信息或者操作文件、文件夹最好用shell命令获取或者操作,而不要用各种API获取或者操作,因为当遇到非法文件夹名或非法文件名或非法文件长度、非法文件日期、压缩文件、链接文件、稀疏文件……等各种意料之外的情况时,API会处理的不全面或陷入死循环,而shell命令不会。
那例如boost::filesystem这种库呢,用这种东西好还是shell好?
「已注销」 2015-07-23
  • 打赏
  • 举报
回复
这是个人写过的模拟 Windows API 中 EnumWindows、EnumFontFamilies 之类的方式,可以将一个回调函数地址作为参数,对于每个找到的文件调用该函数。并且还可以额外传递一个参数,当回调函数调用的时候可以拿到。这样扩展性高一些。还根据这个扩展出支持文件名通配符(使用 PathMatchSpec 匹配)的函数。以下只是个简单的例子,仅仅递归查找文件并调用回调函数打出文件路径。
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

typedef BOOL (CALLBACK *FINDFILESPROC)(LPCTSTR, LPARAM);

BOOL CALLBACK ShowFoundFiles(LPCTSTR pszFile, LPARAM lParam);

BOOL WINAPI FindAllFilesRecursively(LPCTSTR, FINDFILESPROC, LPARAM);

int __cdecl main(
    int argc,
    char *argv[]
)
{
    // 返回 TRUE 表示成功,FALSE 表示失败或 ShowFoundFiles 返回 FALSE
    BOOL fResult = FindAllFilesRecursively(TEXT("D:"), ShowFoundFiles, 0);
    printf("FindAllFilesRecursively returned: %d\n", fResult);
    return 0;
}

BOOL CALLBACK ShowFoundFiles(
    LPCTSTR pszFile,
    LPARAM lParam
)
{
    _tprintf(TEXT("%s\n"), pszFile);
    // 返回 TRUE 继续查找,返回 FALSE 终止。
    return TRUE;
}

BOOL WINAPI FindAllFilesRecursively(
    LPCTSTR pszRootPath,
    FINDFILESPROC ffproc,
    LPARAM lpParam
)
{
    TCHAR szFileFind[MAX_PATH] = { 0 };
    if (PathCombine(szFileFind, pszRootPath, TEXT("*.*")) == NULL)
    {
        SetLastError(ERROR_INVALID_NAME);
        return FALSE;
    }
    WIN32_FIND_DATA wfd = { 0 };
    HANDLE hFindFile = FindFirstFile(szFileFind, &wfd);
    if (hFindFile == INVALID_HANDLE_VALUE)
    {
        SetLastError(ERROR_INVALID_NAME);
        return FALSE;
    }
    __try {
        do {
            if ((lstrcmpi(wfd.cFileName, TEXT(".")) != 0) &&
                (lstrcmpi(wfd.cFileName, TEXT("..")) != 0))
            {
                BOOL fResult = FALSE;
                TCHAR szNextPath[MAX_PATH] = { 0 };
                if (PathCombine(szNextPath, pszRootPath, wfd.cFileName) == NULL)
                {
                    return FALSE;
                }
                if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                    fResult = FindAllFilesRecursively(szNextPath, ffproc, lpParam);
                }
                else
                {
                    fResult = ffproc(szNextPath, lpParam);
                }
                if (!fResult)
                {
                    return FALSE;
                }
            }
        } while (FindNextFile(hFindFile, &wfd));
    }
    __finally {
        FindClose(hFindFile);
    }
    return TRUE;
}
对于文件路径的处理,我个人更偏好使用来自 shlwapi.dll 中的 Windows API 系列:
// 扩展名相关操作
PathAddExtension
PathFindExtension
PathRemoveExtension
PathRenameExtension
// 附加路径或组合两个路径
PathAppend
PathCombine
// 判断是否根目录或文件夹
PathIsRoot
PathIsDirectory
// 文件是否存在
PathFileExists
// 文件名是否合法
PathIsFileSpec
// 获取或移除命令行参数
PathGetArgs
PathRemoveArgs
// 文件名是否匹配通配符
PathMatchSpec
// 得到一个文件夹相对于另一文件夹的相对路径
PathRelativePathTo
// 查找文件名
PathFindFileName
// 移除文件名
PathRemoveFileSpec
系统 API 的好处,如 PathAppend 和 PathCombine 无需考虑路径反斜线以及相对路径,系统均能正确处理。如:
TCHAR szDir[MAX_PATH] = TEXT("D:");
TCHAR szRet[MAX_PATH] = { 0 };
// 以下8行的结果都是一样: C:\WINDOWS
PathCombine(szRet, TEXT("C:"), TEXT("WINDOWS"));
PathCombine(szRet, TEXT("C:"), TEXT(".\\WINDOWS"));
PathCombine(szRet, TEXT("C:"), TEXT("Program Files\\..\\WINDOWS"));
PathCombine(szRet, TEXT("C:"), TEXT(".\\Program Files\\..\\WINDOWS"));
PathCombine(szRet, TEXT("C:\\"), TEXT("WINDOWS"));
PathCombine(szRet, TEXT("C:\\"), TEXT(".\\WINDOWS"));
PathCombine(szRet, TEXT("C:\\"), TEXT("Program Files\\..\\WINDOWS"));
PathCombine(szRet, TEXT("C:\\"), TEXT(".\\Program Files\\..\\WINDOWS"));
// 以下任意一行的结果都是一样: D:\WINDOWS
PathAppend(szDir, TEXT("WINDOWS"));
PathAppend(szDir, TEXT(".\\WINDOWS"));
PathAppend(szDir, TEXT("Program Files\\..\\WINDOWS"));
PathAppend(szDir, TEXT(".\\Program Files\\..\\WINDOWS"));
赵4老师 2015-07-23
  • 打赏
  • 举报
回复
system("dir /b /a-d /s c:\\*.* >d:\\allfilesinsub.txt"); //读文件d:\\allfilesinsub.txt的内容即C:\\下所有文件的名字包含子目录 请记住,能用shell命令获取文件、文件夹信息或者操作文件、文件夹最好用shell命令获取或者操作,而不要用各种API获取或者操作,因为当遇到非法文件夹名或非法文件名或非法文件长度、非法文件日期、压缩文件、链接文件、稀疏文件……等各种意料之外的情况时,API会处理的不全面或陷入死循环,而shell命令不会。
fly_dragon_fly 2015-07-23
  • 打赏
  • 举报
回复
sprintf用得不对,改成这样
//strcat(szTexts,path);
sprintf(szTexts,"%s/%s",path,wfd.cFileName);
飞翔的薄荷 2015-07-23
  • 打赏
  • 举报
回复
初略看了下这样改改。 if((wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) { printf("%s\n",wfd.cFileName); } 你最好还是单步调试把,记得FindClose

64,648

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧