搜索按扩展名过滤的文件会返回太多结果

时间:2017-07-05 08:34:24

标签: c++ file winapi

我正在开发一个必须在Windows操作系统上管理文件的C ++控制台应用程序。我需要获取具有特定扩展名的文件名“列表”。我找到了很多解决方案,建议最多的是以下一个:

HANDLE hFind;
WIN32_FIND_DATA data;

hFind = FindFirstFile("C:\\PWS\\*.sda", &data);
if (hFind != INVALID_HANDLE_VALUE) {
    do {
        cout << data.cFileName << endl;

    } while (FindNextFile(hFind, &data));
    FindClose(hFind);
}

假设我在C:\\PWS文件夹中有这些文件:

  • f001.sdac
  • f002.sda
  • f003.sdab
  • f004.sda

上面的代码打印了所有代码,而我只需要f002.sdaf004.sda

任何提示?

NB:我不想使用boost库。

3 个答案:

答案 0 :(得分:2)

代码还会找到"f001.sdac""f003.sdab",因为FindFirstFile()FindFirstFileEx()都匹配短文件名(8.3)和长文件名。例如,"f001.sdac"的短文件名可能类似于"f~1.sda"

原因是backwards compatibility with 16-bit (sigh!) programs

要解决此问题,请使用FindFirstFile()通配符调用*以匹配所有文件,然后执行自己的过滤,例如调用PathMatchSpec()函数。 PathMatchSpec()仅进行字符串匹配,因此它不具有FindFirstFile()的奇怪行为。

WIN32_FIND_DATAW data;    
HANDLE hFind = FindFirstFileW( L"C:\\PWS\\*", &data );
if( hFind != INVALID_HANDLE_VALUE ) 
{
    do 
    {
        if( ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 && 
            PathMatchSpecW( data.cFileName, L"*.sda" ) )
        {
            std::wcout << data.cFileName << std::endl;
        }
    } 
    while( FindNextFileW( hFind, &data ) );

    FindClose( hFind );
}

旁注:FindFirstFileEx()参数调用值为FindExInfoBasic的{​​{1}},据说&#34; 不查询短文件名&#34;,不是此问题的有效解决方案,因为它仍将匹配短(8.3)文件名。

答案 1 :(得分:0)

这样的事情应该为你过滤结果:

bool hasFileExtension(TCHAR cFileName[], TCHAR* ptcExtension)
{
    bool result = true;
    int iFileNameLength = _tcslen(cFileName);
    int iExtensionLength = _tcslen(ptcExtension);

    if (iFileNameLength >= iExtensionLength)
    {
        for (int i = 1; i < iExtensionLength + 1 && result; i++)
        {
            if (cFileName[iFileNameLength - i] != ptcExtension[iExtensionLength - i])
            {
                result = false;
            }
        }
    }
    else
    {
        result = false;
    }

    return result;
}

void listFilesWithExtension(LPCTSTR lpFileName, TCHAR* ptcExtension)
{
    HANDLE hFind;
    WIN32_FIND_DATA data;

    hFind = FindFirstFile(lpFileName, &data);
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            if (hasFileExtension(data.cFileName, ptcExtension))
            {
                wcout << data.cFileName << endl;
            }
        } while (FindNextFile(hFind, &data));
        FindClose(hFind);
    }
}

int main()
{
    LPCTSTR lpFileName = L"C:\\PWS\\*.sda";
    TCHAR* ptcExtension = _T(".sda");
    listFilesWithExtension(lpFileName, ptcExtension);
    Sleep(5000);
    return 0;
}

答案 2 :(得分:0)

我采用的解决方案如下:

void GetFilesByNameRootAndExtension(const string& dirPath, const string& nameRoot, string& ext, vector<string>& files)
{
    files.clear();

    stringstream ss;
    ss << dirPath << "\\" << nameRoot << "*" << ext;
    string searchKeyS = ss.str();
    const char* searchKey = searchKeyS.c_str();

    WIN32_FIND_DATA data;
    HANDLE hFind = FindFirstFile(searchKey, &data);

    ext = ext.erase(0, 1);
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            string fN = data.cFileName;
            if (fN.substr(fN.find_last_of(".") + 1) == ext) // filtering by extension
                files.push_back(fN);
        } while (FindNextFile(hFind, &data));
        FindClose(hFind);
    }
}

谢谢大家的提示!