У меня есть следующий код для поиска файла в моем продукте:

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 Возвращаются ли результаты кеширования пары API FindFirstFile / FindNextFile?

Кажется, что 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 в моем предыдущем коде? Спасибо.

-2
Jun Ge 13 Июн 2018 в 07:55

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());
1
Remy Lebeau 13 Июн 2018 в 05:54