Поиск файла в C ++ - PullRequest
       9

Поиск файла в C ++

0 голосов
/ 23 апреля 2020

Я новичок в C ++, и мне нужно найти на дисках определенный c файл и отобразить их или вывести их в список.

Вот что у меня есть. Некоторые фрагменты, которые я нашел на форумах, и материалы, которые я добавил.

Мой вопрос: как мне их собрать? Допустим, я ищу файл с именем "test.txt"

Спасибо!

// search for drives

char* szSingleDrive;
DWORD dwSize = MAX_PATH;
char szLogicalDrives[MAX_PATH] = { 0 };
DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives);
UINT logicalDrive = GetDriveType(szLogicalDrives);

bool IsPhysicalDrive(string drives)
{
    if (logicalDrive == 3)
    {
        return logicalDrive;
    }
}

// function to look thru directories.

void FindFile(std::string directory)
{
    std::string tmp = directory + "\\*";
    WIN32_FIND_DATA file;
    HANDLE search_handle = FindFirstFile(tmp.c_str(), &file);
    if (search_handle != INVALID_HANDLE_VALUE)
    {
        std::vector<std::wstring> directories;
        do
        {                                                   
            //std::wcout << file.cFileName << std::endl;
            //::MessageBox(NULL, file.cFileName, "", MB_OK); // message box to verify that it's working
            if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            {
                if ((!lstrcmp(file.cFileName, ".")) || (!lstrcmp(file.cFileName, "..")))
                    continue;
            }
            //std::wcout << file.cFileName << std::endl;
            ::MessageBox(NULL, file.cFileName, "", MB_OK);
            directory += "\\" + std::string(file.cFileName);
            FindFile(directory);
        } 
        while (FindNextFile(search_handle, &file));

        if (GetLastError() != 18) // Error code 18: No more files left
            FindClose(search_handle);
            //CloseHandle(search_handle);

    }
}


FindFile("C:\\");  //  <-- this should spin thru different drives (physical drives from the function)

Ответы [ 3 ]

0 голосов
/ 23 апреля 2020

Вы также можете использовать Windows Поиск Сервис вместо рекурсивной функции. Это значительно увеличит скорость поиска.

Во-первых, вам нужно обязательно проиндексировать диск: Панель управления> Индекс> Изменить, проверить каталоги.

Затем вы можете использовать Windows Поиск в качестве образца:

#include <windows.h>
#include <searchapi.h>
#include <iostream>
#include <atldbcli.h>

using namespace std;

class CMyAccessor
{
public:
    WCHAR _szItemUrl[2048];
    __int64 _size;
    BEGIN_COLUMN_MAP(CMyAccessor)
        COLUMN_ENTRY(1, _szItemUrl)
        COLUMN_ENTRY(2, _size)
    END_COLUMN_MAP()
};
HRESULT GetSQLStringFromParams(LCID lcidContentLocaleParam,
    PCWSTR pszContentPropertiesParam,
    LCID lcidKeywordLocaleParam,
    LONG nMaxResultsParam,
    PCWSTR pszSelectColumnsParam,
    PCWSTR pszSortingParam,
    SEARCH_QUERY_SYNTAX sqsSyntaxParam,
    SEARCH_TERM_EXPANSION steTermExpansionParam,
    PCWSTR pszWhereRestrictionsParam,
    PCWSTR pszExprParam,
    PWSTR* ppszSQL)
{
    ISearchQueryHelper* pQueryHelper;

    // Create an instance of the search manager
    ISearchManager* pSearchManager;
    HRESULT hr = CoCreateInstance(__uuidof(CSearchManager), NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&pSearchManager));
    if (SUCCEEDED(hr))
    {
        // Get the catalog manager from the search manager
        ISearchCatalogManager* pSearchCatalogManager;
        hr = pSearchManager->GetCatalog(L"SystemIndex", &pSearchCatalogManager);

        if (SUCCEEDED(hr))
        {
            // Get the query helper from the catalog manager
            hr = pSearchCatalogManager->GetQueryHelper(&pQueryHelper);
            if (SUCCEEDED(hr))
            {
                hr = pQueryHelper->put_QueryContentLocale(lcidContentLocaleParam);
                if (SUCCEEDED(hr))
                {
                    hr = pQueryHelper->put_QueryContentProperties(pszContentPropertiesParam);
                }
                if (SUCCEEDED(hr))
                {
                    hr = pQueryHelper->put_QueryKeywordLocale(lcidKeywordLocaleParam);
                }
                if (SUCCEEDED(hr))
                {
                    hr = pQueryHelper->put_QueryMaxResults(nMaxResultsParam);
                }
                if (SUCCEEDED(hr))
                {
                    hr = pQueryHelper->put_QuerySelectColumns(pszSelectColumnsParam);
                }
                if (SUCCEEDED(hr))
                {
                    hr = pQueryHelper->put_QuerySorting(pszSortingParam);
                }
                if (SUCCEEDED(hr))
                {
                    hr = pQueryHelper->put_QuerySyntax(sqsSyntaxParam);
                }
                if (SUCCEEDED(hr))
                {
                    hr = pQueryHelper->put_QueryTermExpansion(steTermExpansionParam);
                }
                if (SUCCEEDED(hr))
                {
                    hr = pQueryHelper->put_QueryWhereRestrictions(pszWhereRestrictionsParam);
                }
                if (SUCCEEDED(hr))
                {
                    hr = pQueryHelper->GenerateSQLFromUserQuery(pszExprParam, ppszSQL);
                }
                pQueryHelper->Release();
            }
            pSearchCatalogManager->Release();
        }
        pSearchManager->Release();
    }
    return hr;
}


void WindowsSearch(PCWSTR indexed_drive)
{
    PWSTR pszSQL;
    wstring script = L"AND SCOPE ='file:///";
    script += indexed_drive;
    script += L"'";
    HRESULT hr = GetSQLStringFromParams(1033, L"", 1033, -1, L"System.ItemPathDisplay, System.Size",
        L"", SEARCH_ADVANCED_QUERY_SYNTAX, SEARCH_TERM_NO_EXPANSION, script.c_str(),
        L"FileName:test.txt", &pszSQL);

    if (SUCCEEDED(hr))
    {
        wcout << L"Generated query: " << pszSQL << endl;

        CDataSource cDataSource;
        hr = cDataSource.OpenFromInitializationString(L"provider=Search.CollatorDSO.1;EXTENDED PROPERTIES='Application=Windows'");
        if (SUCCEEDED(hr))
        {
            CSession cSession;
            hr = cSession.Open(cDataSource);
            if (SUCCEEDED(hr))
            {
                // cCommand is derived from CMyAccessor which has binding information in column map
                // This allows ATL to put data directly into apropriate class members.
                CCommand<CAccessor<CMyAccessor>, CRowset> cCommand;
                hr = cCommand.Open(cSession, pszSQL);
                if (SUCCEEDED(hr))
                {
                    __int64 maxValue = 0;
                    __int64 minValue = ULONG_MAX;

                    for (hr = cCommand.MoveFirst(); S_OK == hr; hr = cCommand.MoveNext())
                    {
                        wcout << cCommand._szItemUrl << L": " << cCommand._size << L" bytes" << endl;

                        maxValue = max(maxValue, cCommand._size);
                        minValue = min(minValue, cCommand._size);
                    }

                    wcout << L"Max:" << maxValue << L"Min:" << minValue << endl;

                    cCommand.Close();
                }
                cCommand.ReleaseCommand();
            }
        }
        CoTaskMemFree(pszSQL);
    }
}

int main()
{
    DWORD dwLogicalDrives = GetLogicalDrives();
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
    if (SUCCEEDED(hr) && dwLogicalDrives != 0)
    {
        WCHAR szSingleDrive[] = L"_:\\";
        for (DWORD i = 0; i < 26; ++i)
        {
            if (dwLogicalDrives & (1 << i))
            {
                szSingleDrive[0] = 'A' + i;
                if (GetDriveTypeW(szSingleDrive) == DRIVE_FIXED)
                    WindowsSearch(szSingleDrive);
            }
        }

        CoUninitialize();
    }
}
0 голосов
/ 23 апреля 2020

Вы можете использовать std::filesystem с C ++ 17, обратите внимание, что это может быть доступно на многих компиляторах до C ++ 17, поскольку это необязательная спецификация. Вы также можете использовать boost::filesystem в качестве замены или эту библиотеку только для заголовков на основе спецификации C ++ 17 filesystem

Чтобы найти один файл рекурсивно с помощью std::filesystem вы бы сделали что-то вроде этого:

std::filesystem::path top_level_dir("/");

for (const auto& file_iter : std::filesystem::recursive_directory_iterator(top_level_dir) {
  if (!std::filesystem::is_directory(file_iter.path()) {
    if (file_iter.path() == search_filename) {
      // Here we have found the file
    }
  }
}

(search_filename - имя файла для поиска)

Это далеко более кратко, чем используя windows API, а также более переносим (обратите внимание, как я использую forward sla sh в пути для top_level_dir).

0 голосов
/ 23 апреля 2020

Попробуйте что-то еще подобное:

void FindFile(const std::string &directory)
{
    std::string dir = directory;
    if ((!dir.empty()) && (dir.back() != '\\') && (dir.back() != '/'))
        dir += '\\';

    WIN32_FIND_DATAA file;
    HANDLE search_handle = FindFirstFileA((dir + "*").c_str(), &file);
    if (search_handle == INVALID_HANDLE_VALUE)
    {
        if (GetLastError() != ERROR_FILE_NOT_FOUND)
        {
            // error handling...
        }
    }
    else
    {
        //std::vector<std::string> subdirs;

        do
        {                                                   
            if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            {
                if ((lstrcmpA(file.cFileName, ".") != 0) && (lstrcmpA(file.cFileName, "..") != 0))
                {
                    //std::cout << file.cFileName << std::endl;
                    ::MessageBox(NULL, file.cFileName, "", MB_OK);
                    //subdirs.push_back(file.cFileName);
                    FindFile(dir + file.cFileName);
                }
            }
            else
            {
                if (lstrcmpA(file.cFileName, "test.txt") == 0)
                {
                    ::MessageBox(NULL, dir.c_str(), "FOUND IN DIR", MB_OK);
                }
            }
        } 
        while (FindNextFileA(search_handle, &file));

        if (GetLastError() != ERROR_NO_MORE_FILES)
        {
            // error handling...
        }

        FindClose(search_handle);

        /*
        for(size_t i = 0; i < subdirs.size(); ++i)
            FindFile(dir + subdirs[i]);
        */
    }
}

И тогда вы можете сделать это:


DWORD dwSize = MAX_PATH;
char szLogicalDrives[MAX_PATH];
DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives);
if (dwResult == 0)
{
    // error handling...
}
else if (dwResult > MAX_PATH)
{
    // not enough buffer space...
}
else
{
    for(char* szSingleDrive = szLogicalDrives; *szSingleDrive != 0; szSingleDrive += (lstrlenA(szSingleDrive)+1))
    {
        if (GetDriveTypeA(szSingleDrive) == DRIVE_FIXED)
            FindFile(szSingleDrive);
    }
}

Или вот это:


DWORD dwLogicalDrives = GetLogicalDrives();
if (dwLogicalDrives == 0)
{
    // error handling...
}
else
{
    char szSingleDrive[] = "_:\\";
    for (DWORD i = 0; i < 26; ++i)
    {
        if (dwLogicalDrives & (1 << i))
        {
            szSingleDrive[0] = 'A' + i;
            if (GetDriveTypeA(szSingleDrive) == DRIVE_FIXED)
                FindFile(szSingleDrive);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...