【问题标题】:FindNextFileA returns 6 (ERROR_INVALID_HANDLE)FindNextFileA 返回 6 (ERROR_INVALID_HANDLE)
【发布时间】:2014-02-04 07:15:33
【问题描述】:

有递归查找文件夹中所有文件的功能(存储在logPath文件夹名末尾有'\')。它用于64位控制台应用程序(在MSVC 2008中编译)并在Win7 64位操作系统上运行。

当我运行“program.exe folder_to_find”之类的应用程序时,它运行良好。

当我运行“program.exe folder_to_find >> result.txt”之类的应用程序时,它失败并返回错误 6 (ERROR_INVALID_HANDLE) FindNextFileA(即使没有对大文件夹进行递归调用)。例如。它可以在文件夹中找到前 150 个文件,而不是现有的 240 个。

void FindFiles(const std::string &logPath, FileList& fileList)
{
    WIN32_FIND_DATAA fd;
    HANDLE f = FindFirstFileA((logPath + "*").c_str(), &fd);

    if (f == INVALID_HANDLE_VALUE)
    {
        printf("No files found at %s - %d\n", logPath.c_str(), GetLastError());
        return;
    }

    FileList dirList;
    do
    {
        if (strcmp(fd.cFileName, ".") == 0)
            continue;
        if (strcmp(fd.cFileName, "..") == 0)
            continue;
        std::string path = logPath + fd.cFileName;
        printf("Processing %s\n", path.c_str());
        if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            dirList.push_back(path);
        else
            fileList.push_back(path);
    }
    while (FindNextFileA(f, &fd) != 0);

    DWORD err = GetLastError();
    if (err != ERROR_NO_MORE_FILES)
    {
        printf("Unexpected error in FindNextFileA(%s): %d\n", logPath.c_str(), err);
        fflush(stdout);
        abort();
    }

    FindClose(f);

    //for(FileList::const_iterator it = dirList.begin(); it != dirList.end(); ++it)
    //  FindFiles(*it, fileList);
}

【问题讨论】:

  • 结果文件是在您正在搜索的目录中创建的(还是在您正在搜索的目录的子目录中)?如果是这样,可能在搜索目录时打开文件(并被更改)会导致问题。您可能需要进行一些试验,以了解有关导致此问题的条件的更多信息。
  • 否,结果文件正在目标目录之外创建。至少程序没有打开任何文件。
  • printf?!为什么不使用cout?然后你可以避免那些讨厌的c_str() 电话。您还必须在关联的 API 调用失败后立即调用 GetLastError()。你不会在 Q 的代码中这样做。
  • printf 只是一个坏习惯,对不起。正如我所见,GetLastErrorFindNextFileA 调用之后立即被调用。
  • 那个没问题,但是 FindFirstFileA 之后的那个不行。当然logPath.c_str() 不会有问题,但是当你打电话给GetLastError 时,要非常准确地了解这是一个好习惯。

标签: winapi visual-c++ console-application


【解决方案1】:

我不能说为什么FindFirstFileA() 在使用控制台重定向时会返回那个特定的错误代码(您没有显示如何将结果输出到控制台),但是您的代码中有一些小错误(最明显的是,您没有对FindFirstFileA() 进行足够的错误处理,并且没有通过递归调用FindFiles()\ 附加到目录路径的末尾)。

试试这个:

void FindFiles(const std::string &logPath, FileList& fileList)
{
    WIN32_FIND_DATAA fd;
    DWORD err;

    std::string sLogPath(logPath);
    if (sLogPath.length() > 0)
    {
        if (sLogPath[sLogPath.length()-1] != '\\')
            sLogPath += '\\';
    }

    HANDLE f = FindFirstFileA((sLogPath + "*").c_str(), &fd);
    if (f == INVALID_HANDLE_VALUE)
    {
        err = GetLastError();
        if (err != ERROR_FILE_NOT_FOUND)
        {
            printf("Unexpected error in FindFirstFileA(%s): %d\n", sLogPath.c_str(), err);
            fflush(stdout);
            abort();
        }

        printf("No files found at %s\n", sLogPath.c_str());
        return;
    }

    FileList dirList;
    do
    {
        if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            if ((strcmp(fd.cFileName, ".") != 0) && (strcmp(fd.cFileName, "..") != 0))
            {
                std::string path = sLogPath + fd.cFileName;
                printf("Processing dir %s\n", sLogPath.c_str());
                dirList.push_back(path);
            }
        }
        else
        {
            std::string path = sLogPath + fd.cFileName;
            printf("Processing file %s\n", path.c_str());
            fileList.push_back(path);
        }
    }
    while (FindNextFileA(f, &fd));

    err = GetLastError();
    FindClose(f);

    if (err != ERROR_NO_MORE_FILES)
    {
        printf("Unexpected error in FindNextFileA(%s): %d\n", sLogPath.c_str(), err);
        fflush(stdout);
        abort();
    }

    //for(FileList::const_iterator it = dirList.begin(); it != dirList.end(); ++it)
    //  FindFiles(*it, fileList);
}

【讨论】:

  • 此代码在第 122 个子目录之后导致相同的错误 — 使用控制台重定向时 FindNextFileA(1) 中出现意外错误:6
  • 仔细查看该错误消息。它说logPath"1",这不是一个有效的路径。这应该是您发现有问题的第一个线索。 FindNextFileA() 抱怨 f 不是一个有效的句柄。所以这里显示的代码之外的东西正在破坏内存,你的两个变量都是这种破坏的受害者。 FileList 声明为什么?它是动态增长的还是它可以容纳多少条目有限制?
  • 我已将您的代码 logPath + "*" 更改为 logPath + "\\*" 以运行。 FileList 声明为 typedef std::vector<std::string> FileList;。我依赖 STL。 :) 没有外部代码——除了这段代码和main 之外,我已经注释了所有代码,我将argv[1] 传递给FindFiles
  • 如果您将过滤器更改为使用+"\\*",那么您必须在递归循环中调用FindFiles() 时删除+"\\",并且您必须确保不要将'\' 包含在argv[1] 值的结尾。我建议让FindFiles()logPath 分配给一个局部变量,如果缺少,将"\\" 附加到它的末尾,然后在任何地方使用该变量而不是直接使用logPath。但这仍然不能解释为什么logPath"1"f 在发生故障时无效。这仍然表明内存损坏。
【解决方案2】:

有一个boost::thread t,我用HANDLE h = t.native_handle() 存储它的句柄

有一个电话 CloseHandle(h) 稍后关闭它。

我忘了,然后boost::~thread()析构函数也关闭了它的句柄。

在我复制线程句柄后
HANDLE h = NULL;
::DuplicateHandle(..., t.native_handle(), &h, ...)
在关闭之前 - 问题消失了......

【讨论】:

  • 你为什么要手动关闭线程句柄?为什么不让boost::thread 为您处理呢?
  • 这段代码是另一个应用程序测试的一部分,CloseHandle 用于关闭进程句柄,线程将模仿此进程的行为。
猜你喜欢
  • 1970-01-01
  • 2020-12-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-19
  • 1970-01-01
  • 2020-09-13
  • 1970-01-01
  • 2023-03-27
相关资源
最近更新 更多