FindFirstFile API没有找到目录中的所有文件

时间:2018-06-13 04:55:21

标签: c++ windows api sdk

我有以下代码在我的产品中查找文件:

destFolder = "c:\\myproduct\\base\\";

//download and unzip whoisactive.zip from some websites to the installation folder of my product
DownloadAndUnzipSql( "http://www.whoisactive.com/whoisactive.zip", destFolder)

WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile(destFolder.c_str(), &ffd);

do {
    if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
        if ((string(ffd.cFileName).find("whoisactive") != string::npos) && (string(ffd.cFileName).find("sql") != string::npos)){
            MoveFile(ffd.cFileName, sqlFile.c_str());
            log.Debug(__FUNCTION__, "Succeed to rename file.");
            break;
        }
    }
} while (FindNextFile(hFind, &ffd) != 0);           

FindClose(hFind);

以前工作得非常好,但它最近一个月内无法找到下载的whoisactive.sql。我检查了c:\ myproduct \ base \,whoisactive.sql在那里,但当我转储所有文件FindFirstFile和FindNextFile返回时,没有包含whoisactive.sql。

我不认为它是由防病毒软件引起的,因为在产品环境中没有安装此类软件。我并不认为它的权限问题,因为whoisactive.sql是正确下载和解压缩的。

我搜索了我的问题,发现了以下两篇文章: https://social.msdn.microsoft.com/Forums/vstudio/en-US/4659a528-dd51-4749-b751-a491bbdf5fa0/findfirstfile-caching?forum=vcgeneral Does FindFirstFile/FindNextFile API pair cache results returned?

似乎FindFirstFile将缓存目录的文件列表,因此有时我们可能找不到新添加的文件。但我也不认为这也是根本原因,因为我的代码在去年运行得很好并且从未失败,这很奇怪,而且最近一个月找不到whoisactive.sql突然间,直到现在都没有工作。如果缓存问题是根本原因,那么为什么我现在总能重现问题呢?奇怪的是代码仍然可以在我的开发环境中工作,但它不能在产品环境中工作。

所以我将代码更改为以下内容,然后它在产品和开发环境中都有效:

destFolder = "c:\\myproduct\\base\\";

//download whoisactive.zip from some websites to the installation folder of my product
Download( "http://www.whoisactive.com/whoisactive.zip", destFolder);

//Unzip the whoisactive.zip and get the extracted file list.
string fileList;
Unzip(destFolder+"\\whoisactive.zip", fileList);

for (int i=0; i<fileList.size(); ++i) {
    if (fileList[i].find("sql") != string::npos && fileList[i].find("whoisactive") != string::npos) {
        string srcFile = destFolder+"\\"+fileList[i];
        string dstFile = destFolder+"\\"+sqlFile;

        if (DeleteFile(dstFile.c_str()) == 0)
            log.Debug(__FUNCTION__, "Failed to delete file %s, error code is %d.", dstFile.c_str(), GetLastError());

        if (MoveFile(srcFile.c_str(), dstFile.c_str()) == 0)
            log.Debug(__FUNCTION__, "Failed to rename file %s, error code is %d.", srcFile.c_str(), GetLastError());

        break;
    }
}

您可以看到更改是我不再在我的代码中使用FindFirstFile和FindNextFile,我只是从zip文件中提取文件名并直接访问该文件。那么请你告诉我为什么FindFirstFile和FindNextFile在我以前的代码中找不到下载的sql文件?感谢。

1 个答案:

答案 0 :(得分:1)

您根本没有搜索目录的内容。您正在将目录本身原样("c:\\myproduct\\base\\")传递给FindFirstFile(),这样就可以找到 - 目录本身的属性,没有别的。

要正确枚举目录,您需要执行通配符搜索。将**.*附加到目录路径的末尾,例如:

destFolder = "c:\\myproduct\\base\\";

//download and unzip whoisactive.zip from some websites to the installation folder of my product
DownloadAndUnzipSql("http://www.whoisactive.com/whoisactive.zip", destFolder);

WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFileA((destFolder + "*.*").c_str(), &ffd);
if (hFind != INVALID_HANDLE_VALUE) {
    do {
        if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
            if (lstrcmpiA(ffd.cFileName, "whoisactive.sql") == 0) {
                if (MoveFileA((destFolder + ffd.cFileName).c_str(), (destFolder + sqlFile).c_str()))
                    log.Debug(__FUNCTION__, "Succeed to rename file.");
                else
                    log.Debug(__FUNCTION__, "Failed to rename file, error code is %d.", GetLastError());
                break;
            }
        }
    }
    while (FindNextFileA(hFind, &ffd));

    if (GetLastError() != ERROR_NO_MORE_FILES) {
        log.Debug(__FUNCTION__, "Failed to find next file, error code is %d.", GetLastError());
    }

    FindClose(hFind);
}
else if (GetLastError() == ERROR_FILE_NOT_FOUND) {
    log.Debug(__FUNCTION__, "No files found.");
}
else {
    log.Debug(__FUNCTION__, "Failed to find first file, error code is %d.", GetLastError());
}

但是,由于您只对特定文件感兴趣,因此根本不需要使用Find(First|Next)File()。只要无条件地调用MoveFile(),如果文件不存在就让它失败:

destFolder = "c:\\myproduct\\base\\";

//download and unzip whoisactive.zip from some websites to the installation folder of my product
DownloadAndUnzipSql("http://www.whoisactive.com/whoisactive.zip", destFolder);

if (MoveFileA((destFolder + "whoisactive.sql").c_str(), (destFolder + sqlFile).c_str()))
    log.Debug(__FUNCTION__, "Succeed to rename file.");
else
    log.Debug(__FUNCTION__, "Failed to rename file, error code is %d.", GetLastError());