【问题标题】:DeleteFile which begin with substring以子字符串开头的 DeleteFile
【发布时间】:2019-02-12 01:34:27
【问题描述】:

我想删除所有以子字符串开头的文件。

  CString Formatter = _T("C:\\logs\\test\\test_12-12-2018_1*.*");     
  DeleteFile(Formatter);

我打算用上面的代码删除以下文件

    C:\logs\test\test_12-12-2018_1_G1.txt
    C:\logs\test\test_12-12-2018_1_G2.txt
    C:\logs\test\test_12-12-2018_1_G3.txt
    C:\logs\test\test_12-12-2018_1_G4.txt

当我从 GetLastError 检查错误时,我得到 ERROR_INVALID_NAME。

知道如何解决这个问题吗?

【问题讨论】:

  • DeleteFile 函数不使用通配符。您必须自己 find 文件。
  • 你可以做system ("del C:\\logs\\test\\test_12-12-2018_1*.*");
  • @PaulSanders 一个非常丑陋的解决方案。
  • @Jabberwocky 为什么?
  • @PaulSanders 因为正确的方法是按照公认的答案建议的那样去做。如果我继续你的推理,为什么不使用system("echo Hello world"); 而不是printf("Hello World");

标签: c++ winapi


【解决方案1】:

DeleteFile 不接受通配符。看起来您需要一个 FindFirstFile/FindNextFile/FindClose 循环将您的通配符转换为完整文件名列表。

#include <windows.h>
#include <pathcch.h>
#pragma comment(lib, "pathcch.lib")

// (In a function now)
WIN32_FIND_DATAW wfd;
WCHAR wszPattern[MAX_PATH];
HANDLE hFind;
INT nDeleted = 0;
PathCchCombine(wszPattern, MAX_PATH, L"C:\\Logs\\Test", L"test_12-12-2018_1*.*");
SetCurrentDirectoryW(L"C:\\Logs\\Test");

hFind = FindFirstFileW(wszPattern, &wfd);
if(hFind == INVALID_HANDLE_VALUE)
{
    // Handle error & exit
}
do
{
    DeleteFileW(wfd.cFileName);
    nDeleted++;
} 
while (FindNextFileW(hFind, &wfd));
FindClose(hFind);

wprintf(L"Deleted %d files.\n", nDeleted);

请注意,PathCchCombineFindFirstFileWDeleteFileW 都可能失败,健壮的代码会检查它们的返回值并适当地处理失败。此外,如果FindNextFileW 返回 0 并且最后一个错误代码不是ERROR_NO_MORE_FILES,那么它由于实际错误(而不是因为没有什么可查找)而失败,这也需要处理。

另外,如果您关心速度(您在帖子中关于删除同一目录中的四个文件的示例似乎不需要它),请将hFind = FindFirstFileW(...) 行替换为:

hFind = FindFirstFileExW(wszPattern, FindExInfoBasic, (LPVOID)&wfd, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);

【讨论】:

  • 但是需要if (INVALID_HANDLE_VALUE != hFind) 并更好地使用FindFirstFileExWFIND_FIRST_EX_LARGE_FETCHFindExInfoBasic
  • @RbMm added INVALID_HANDLE_VALUE check,但是,我认为这种简单的操作不需要-Ex 变体(OP显示意图删除单个目录中的某些文件,而不是在目录树的下方)
  • 简单的FindFirstFileExW 加上FIND_FIRST_EX_LARGE_FETCHFindExInfoBasic 非常显着的提高性能,无关我们是否需要遍历目录树
  • @RbMm 将该信息作为选项添加到我的帖子中(不在主代码中),因为我认为优化不会真正有利于 OP 的四个文件的简单示例
【解决方案2】:

虽然您可以搜索文件名,然后为每个文件单独调用 DeleteFile,但我的建议是使用 Windows shell 函数之一来代替。

例如,您可以使用如下代码:

#define _WIN32_IE 0x500

#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#include <iostream>
#include <string>

static char const *full_path(std::string const &p) {
    static char path[MAX_PATH+2] = {0};
    char *ignore;
    GetFullPathName(p.c_str(), sizeof(path), path, &ignore);
    return path;
}

static int shell_delete(std::string const &name) {
    SHFILEOPSTRUCT op = { 0 };

    op.wFunc = FO_DELETE;
    op.pFrom = full_path(name);
    op.fFlags = FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING | FOF_NOCONFIRMATION;
    return !SHFileOperation(&op);
}

int main(int argc, char **argv) {

    if ( argc < 2) {
        fprintf(stderr, "Usage: delete <filename> [filename ...]");
        return 1;
    }

    for (int i=1; i<argc; i++)
        shell_delete(argv[i]);    
}

这样做的一个明显优势是您可以传递FOF_ALLOWUNDO 标志(正如我在上面的代码中所做的那样),它将文件移动到回收站而不是永久删除它。当然,如果你想对文件进行 nuked,你可以省略该标志。

根据您正在执行的操作,还有一些其他标志可能会很方便,例如 FOF_FILESONLY,用于仅删除文件,而不是可能与您指定的通配符匹配的目录,以及 FOF_NORECURSION 拥有它根本不递归到子目录。

Microsoft 认为 SHFileOperation 已过时,并已(在 Windows Vista 中,如果没记错的话)将其“替换”为 IFileOperationIFileOperation 是一个 COM 接口,所以除非您在代码的其他地方使用 COM,否则使用它很可能会增加相当多的额外工作(至少在这种情况下)很少或没有真正的优势。尤其是您已经在使用 COM,但是,这可能值得考虑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 2015-01-28
    相关资源
    最近更新 更多