Copy all files .doc or .docx in folder and subfolder into another folder

Viewed 150

I am new to C++ and winapi, currently working on a project to create a winapi application with a function to copy all files .doc and .docx in one drive to another folder. Below is what I have done and it doesn't seem to work:

Can anyone show me how to do this properly ?

void  cc(wstring inputstr) {
    TCHAR sizeDir[MAX_PATH];
    wstring search = inputstr + TEXT("\\*");
    wcscpy_s(sizeDir, MAX_PATH, search.c_str());

WIN32_FIND_DATA findfiledata;
HANDLE Find = FindFirstFile(sizeDir, &findfiledata);

do {

    if (findfiledata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
        if (!wcscmp(findfiledata.cFileName, TEXT(".")) || !wcscmp(findfiledata.cFileName, TEXT(".."))) continue;
        //checking folder or file
        wstring dirfolder = inputstr + TEXT("\\") + findfiledata.cFileName;
        cc(dirfolder);
    }
    else {
        wstring FileSearch = findfiledata.cFileName;
        //.doc or docx
        if (!wcscmp(FileSearch.c_str(), L".doc") || !wcscmp(FileSearch.c_str(), L".docx")) {
            TCHAR src[256] = L"D:\\test\\";
            wstring dirsrc = inputstr + TEXT("\\") + findfiledata.cFileName;
            _tprintf(TEXT("  %s  \n"), dirsrc.c_str());
            wcscat_s(src, findfiledata.cFileName);
            CopyFile(dirsrc.c_str(), src, TRUE);
        }
    }

} while (FindNextFile(Find, &findfiledata) != 0); 
FindClose(Find);
}

The inputstr here when i call the function is the drive that i want to search like cc(L"D:");

1 Answers
if (!wcscmp(FileSearch.c_str(), L".doc") || !wcscmp(FileSearch.c_str(), L".docx"))

This is comparing the whole file name. We only need to compare the file extension. PathFindExtension can be used to find the file extension:

const wchar_t* ext = PathFindExtension(findfiledata.cFileName);
if (_wcsicmp(ext, L".doc") == 0 || _wcsicmp(ext, L".docx") == 0)
{
    const std::wstring path = inputstr + L"\\" + findfiledata.cFileName;
    std::wcout << path << '\n';
}

findfiledata should be zero initialized.

Adding CopyFile inside that recursive function may cause problems. Because FindNextFile could see the new copied file, and the function tries to copy it again.

You could instead save the result in a vector of strings, then copy the file once cc is finished.

void cc(const std::wstring &inputstr, std::vector<std::wstring> &vec)
{
    std::wstring wildcard{ inputstr + L"\\*" };
    WIN32_FIND_DATA find = { 0 };
    HANDLE handle = FindFirstFile(wildcard.c_str(), &find);
    if (handle == INVALID_HANDLE_VALUE)
        return;
    do
    {
        if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            if (!wcscmp(find.cFileName, L".") || !wcscmp(find.cFileName, L".."))
                continue;
            const std::wstring dir = inputstr + L"\\" + find.cFileName;
            cc(dir, vec);
        }
        else 
        {
            const wchar_t* ext = PathFindExtension(find.cFileName);
            if (_wcsicmp(ext, L".doc") == 0 || _wcsicmp(ext, L".docx") == 0)
            {
                const std::wstring path = inputstr + L"\\" + find.cFileName;
                vec.push_back(path);
            }
        }
    } while (FindNextFile(handle, &find) != 0);
    FindClose(handle);
}

Used as

std::vector<std::wstring> result;
cc(L"D:\\test", result);
for (const auto& e : result)
    std::wcout << e << '\n';

Note, PathFindExtension requires additional headers and libraries. If it's not available for some reason, and std::filesystem is not available, here is a do it yourself method:

std::wstring test = findfiledata.cFileName;
auto dot = test.find_last_of(L'.');
if (dot != std::wstring::npos)
{
    auto ext = test.substr(dot);
    for (auto& e : ext) e = towlower(e);
    if (ext == L".doc" || ext == L".docx")
    {
        std::wstring path = inputstr + L"\\" + findfiledata.cFileName;
        std::wcout << path << '\n';
    }
}
Related