【问题标题】:C++ folder wont delete until I close program在我关闭程序之前,C++ 文件夹不会删除
【发布时间】:2014-04-11 20:48:38
【问题描述】:

在我正在制作的游戏中,带有文本文件的文件夹代表世界保存,在这个游戏的加载菜单中,我希望有一个删除保存的选项。我目前正在使用此代码来尝试删除保存:

hFind = FindFirstFile((dir+"/*").c_str(), &FindFileData);
if (hFind){
    do{
        string s = FindFileData.cFileName;
        if(s.find('.')){//prevents prossesing of "." and ".."
            DeleteFile((dir+"/"+s).c_str());
        }
    }while(FindNextFile(hFind,&FindFileData));
    CloseHandle(hFind);
}
rmdir(dir.c_str());

这些文件夹中唯一的东西是 3 个文本文件,所以这段代码应该足够了,但事实并非如此。发生的情况是目录中的所有文件都被删除,而不是文件夹,如果我尝试手动删除这个文件夹,或者在程序运行时以任何方式编辑它,Windows 拒绝我访问。但是一旦我关闭游戏,文件夹就会被删除。

我知道里面的文件被删除了,因为我尝试了上面没有“rmdir(dir.c_str());”的代码并打开文件夹,所有文件都消失了,如果我“删除”保存然后尝试加载它,也使用上面的代码我没有世界,也没有库存,表明文件已被删除。

我用 removeDirectory 试过了,同样的事情发生了,它还说它被成功删除,没有任何错误。

为什么会这样?我怎样才能避免这种情况,并让它正常工作?

任何帮助将不胜感激。


问题已通过以下代码修复:

hFind = FindFirstFile((dir+"/*").c_str(), &FindFileData);
if (hFind){
    do{
        string s = FindFileData.cFileName;
        if(s.find('.')){//prevents prossesing of "." and ".."
            DeleteFile((dir+"/"+s).c_str());
        }
    }while(FindNextFile(hFind,&FindFileData));
    CloseHandle(hFind);
}
findClose(hFind);
rmdir(dir.c_str());

【问题讨论】:

  • 您应该坚持使用 API 并使用 RemoveDirectory。 msdn.microsoft.com/en-us/library/aa365488%28VS.85%29.aspx 如果删除失败,检查错误返回码并调用GetLastError()。 rmdir() 不会给你这个信息(或者至少,很容易)。
  • 您还应该检查DeleteFile是否成功。
  • 使用 RemoveDirectory 会发生同样的事情,除非我多次单击删除,否则不会发生错误,因为程序必须认为该目录已被删除
  • 程序运行时删除文件夹后,刷新资源管理器视图后文件夹是否仍然存在?
  • 是的,它仍然存在,我用来显示已保存世界的系统是实时的,所以如果我去手动删除一个世界,当我单击删除保存时,我会看到它在程序中消失留在那里,

标签: c++ windows


【解决方案1】:

根据RemoveDirectory 文档:

RemoveDirectory 函数在关闭时标记要删除的目录。因此,在关闭该目录的最后一个句柄之前,不会删除该目录。

可能您的程序将该目录作为其当前工作目录,或者可能仍然有打开它的句柄。

在windows中,rmdir是一个调用原生windows函数的比较函数,所以它的行为是一样的。

【讨论】:

  • 好吧,我关闭了我打开的唯一句柄,除非还有更多我不知道的句柄,这不应该是问题。我怎么知道它是否是我当前的工作目录,以及如何更改它?
  • 你可以试试 GetCurrentDirectory / SetCurrentDirectory msdn.microsoft.com/en-us/library/windows/desktop/…
  • 您也可以使用 ProcessExplorer 查看打开了哪些句柄stackoverflow.com/a/15722/1411457
  • 是的,我用 SetCurrentDirectory 更改了当前目录,同样的事情正在发生
  • 好的,我得到它的工作,我正在阅读这个我刚刚找到stackoverflow.com/questions/10832251/…并尝试添加'FindClose(hFind);'就在 RemoveDirectory 之前,它起作用了,对不起,我浪费了您的时间,感谢您的帮助
【解决方案2】:

根本问题是FindFirstFile返回的句柄上调用CloseHandle而不是FindClose的代码。

但是代码还有几个错误。为了帮助未来的访问者,这是更正的代码。

HANDLE hFind = FindFirstFile((dir + "\\*").c_str(), &FindFileData);  // See 1 below
if (hFind != INVALID_HANDLE_VALUE) {  // 2
    do {
        if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {  // 3
            const std::string s = dir + "\\" + FindFileData.cFileName;
            DeleteFile(s.c_str());
        }
    } while (FindNextFile(hFind, &FindFileData));
    // 4
    FindClose(hFind);  // 5
}
RemoveDirectory(dir.c_str());  // 6
  1. Windows 路径使用\ 而不是/ 作为分隔符。许多 API 都可以接受,但最终您会遇到一个不接受的,因此最好始终使用正确的。

  2. FindFirstFile 在失败时返回 INVALID_HANDLE_VALUE(非 NULL)。由于 INVALID_HANDLE_VALUE 不为零,因此您不能简单地测试 if (hFile) { ... }

  3. API 枚举文件和目录。旧代码试图错误地过滤掉... 目录,这可能导致它跳过一些文件并尝试在其他目录上使用DeleteFile。跳过所有目录更简单(也更容易理解)。

  4. 不要在 FindFirstFile 返回的句柄上调用 CloseHandle。

  5. 对 FindFirstFile 返回的句柄调用 FindClose,但仅在您从 FindFirstFile 获得有效句柄的情况下才这样做。

  6. 只要您使用的是特定于 Windows 的 API,您最好始终如一地使用它们,而不是与 rmdir 之类的库包装器混合使用。库包装器有时会引入令人惊讶的限制或行为,尽管我认为 rmdir 在这种情况下可以正常工作。

这仍然留下了一个重大问题:它不处理路径中的 Unicode(并且它要求您针对 ANSI 进行编译,这限制了项目其他部分的 Unicode 处理)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-02
    • 2013-02-20
    • 2018-08-20
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    • 2011-05-05
    相关资源
    最近更新 更多