我如何将FindXFile风格的API包装到C++中的STL样式迭代器模式中?

Bil*_*eal 3 c++ winapi iterator

我正在努力将FindFirstFile/ FindNextFileloop中的丑陋内容(尽管我的问题适用于其他类似的API,例如RegEnumKeyExRegEnumValue等)在迭代器内部以类似于标准模板库的方式工作istream_iterator.

我这里有两个问题.第一个是大多数"foreach"风格循环的终止条件.STL样式迭代器通常operator!=在for的退出条件内使用,即

std::vector<int> test;
for(std::vector<int>::iterator it = test.begin(); it != test.end(); it++) {
 //Do stuff
}
Run Code Online (Sandbox Code Playgroud)

我的问题是我不确定如何operator!=使用这样的目录枚举来实现,因为我不知道枚举何时完成,直到我实际完成它.我现在有一个混合解决方案,它现在枚举整个目录,每个迭代器只是跟踪引用计数向量,但这似乎是一个可以做得更好的方法的kludge.

我遇到的第二个问题是FindXFile API返回了多个数据.因此,operator*根据迭代器语义的要求,没有明显的重载方法.当我重载该项时,是否返回文件名?尺寸?修改日期?我怎样才能传达这样一个迭代器必须在后来以一种思维方式引用的多个数据?我试过扯掉C#风格的MoveNext设计,但我担心这里没有遵循标准的习语.

class SomeIterator {
public:
 bool next(); //Advances the iterator and returns true if successful, false if the iterator is at the end.
 std::wstring fileName() const;
 //other kinds of data....
};
Run Code Online (Sandbox Code Playgroud)

编辑:调用者看起来像:

SomeIterator x = ??; //Construct somehow
while(x.next()) {
    //Do stuff
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

Billy3

编辑2:我修复了一些错误并编写了一些测试.

执行:

#pragma once
#include <queue>
#include <string>
#include <boost/noncopyable.hpp>
#include <boost/make_shared.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <Windows.h>
#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
#include "../Exception.hpp"

namespace WindowsAPI { namespace FileSystem {

template <typename Filter_T = AllResults, typename Recurse_T = NonRecursiveEnumeration>
class DirectoryIterator;

//For unit testing
struct RealFindXFileFunctions
{
    static HANDLE FindFirst(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) {
        return FindFirstFile(lpFileName, lpFindFileData);
    };
    static BOOL FindNext(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) {
        return FindNextFile(hFindFile, lpFindFileData);
    };
    static BOOL Close(HANDLE hFindFile) {
        return FindClose(hFindFile);
    };
};

inline std::wstring::const_iterator GetLastSlash(std::wstring const&pathSpec) {
    return std::find(pathSpec.rbegin(), pathSpec.rend(), L'\\').base();
}

class Win32FindData {
    WIN32_FIND_DATA internalData;
    std::wstring rootPath;
public:
    Win32FindData(const std::wstring& root, const WIN32_FIND_DATA& data) :
        rootPath(root), internalData(data) {};
    DWORD GetAttributes() const {
        return internalData.dwFileAttributes;
    };
    bool IsDirectory() const {
        return (internalData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
    };
    bool IsFile() const {
        return !IsDirectory();
    };
    unsigned __int64 GetSize() const {
        ULARGE_INTEGER intValue;
        intValue.LowPart = internalData.nFileSizeLow;
        intValue.HighPart = internalData.nFileSizeHigh;
        return intValue.QuadPart;
    };
    std::wstring GetFolderPath() const {
        return rootPath;
    };
    std::wstring GetFileName() const {
        return internalData.cFileName;
    };
    std::wstring GetFullFileName() const {
        return rootPath + L"\\" + internalData.cFileName;
    };
    std::wstring GetShortFileName() const {
        return internalData.cAlternateFileName;
    };
    FILETIME GetCreationTime() const {
        return internalData.ftCreationTime;
    };
    FILETIME GetLastAccessTime() const {
        return internalData.ftLastAccessTime;
    };
    FILETIME GetLastWriteTime() const {
        return internalData.ftLastWriteTime;
    };
};

template <typename FindXFileFunctions_T>
class BasicNonRecursiveEnumeration : public boost::noncopyable
{
    WIN32_FIND_DATAW currentData;
    HANDLE hFind;
    std::wstring currentDirectory;
    void IncrementCurrentDirectory() {
        if (hFind == INVALID_HANDLE_VALUE) return;
        BOOL success =
            FindXFileFunctions_T::FindNext(hFind, &currentData);
        if (success)
            return;
        DWORD error = GetLastError();
        if (error == ERROR_NO_MORE_FILES) {
            FindXFileFunctions_T::Close(hFind);
            hFind = INVALID_HANDLE_VALUE;
        } else {
            WindowsApiException::Throw(error);
        }
    };
    bool IsValidDotDirectory()
    {
        return !Valid() &&
            (!wcscmp(currentData.cFileName, L".") || !wcscmp(currentData.cFileName, L".."));
    };
    void IncrementPastDotDirectories() {
        while (IsValidDotDirectory()) {
            IncrementCurrentDirectory();
        }
    };
    void PerformFindFirstFile(std::wstring const&pathSpec)
    {
        hFind = FindXFileFunctions_T::FindFirst(pathSpec.c_str(), &currentData);
        if (Valid()
            && GetLastError() != ERROR_PATH_NOT_FOUND
            && GetLastError() != ERROR_FILE_NOT_FOUND)
            WindowsApiException::ThrowFromLastError();
    };
public:
    BasicNonRecursiveEnumeration() : hFind(INVALID_HANDLE_VALUE) {};
    BasicNonRecursiveEnumeration(const std::wstring& pathSpec) :
        hFind(INVALID_HANDLE_VALUE) {
        std::wstring::const_iterator lastSlash = GetLastSlash(pathSpec);
        if (lastSlash != pathSpec.begin())
            currentDirectory.assign(pathSpec.begin(), lastSlash-1);
        PerformFindFirstFile(pathSpec);
        IncrementPastDotDirectories();
    };
    bool equal(const BasicNonRecursiveEnumeration<FindXFileFunctions_T>& other) const {
        if (this == &other)
            return true;
        return hFind == other.hFind;
    };
    Win32FindData dereference() {
        return Win32FindData(currentDirectory, currentData);
    };
    void increment() {
        IncrementCurrentDirectory();
    };
    bool Valid() {
        return hFind == INVALID_HANDLE_VALUE;
    };
    virtual ~BasicNonRecursiveEnumeration() {
        if (!Valid())
            FindXFileFunctions_T::Close(hFind);
    };
};

typedef BasicNonRecursiveEnumeration<RealFindXFileFunctions> NonRecursiveEnumeration;

template <typename FindXFileFunctions_T>
class BasicRecursiveEnumeration : public boost::noncopyable
{
    std::wstring fileSpec;
    std::deque<std::deque<Win32FindData> > enumeratedData;
    void EnumerateDirectory(const std::wstring& nextPathSpec) {
        std::deque<Win32FindData> newDeck;
        BasicNonRecursiveEnumeration<FindXFileFunctions_T> begin(nextPathSpec), end;
        for(; !begin.equal(end); begin.increment()) {
            newDeck.push_back(begin.dereference()); 
        }
        if (!newDeck.empty()) {
            enumeratedData.push_back(std::deque<Win32FindData>()); //Swaptimization
            enumeratedData.back().swap(newDeck);
        }
    };
    void PerformIncrement() {
        if (enumeratedData.empty()) return;
        if (enumeratedData.back().front().IsDirectory()) {
            std::wstring nextSpec(enumeratedData.back().front().GetFullFileName());
            nextSpec.append(L"\\*");
            enumeratedData.back().pop_front();
            EnumerateDirectory(nextSpec);
        } else {
            enumeratedData.back().pop_front();
        }
        while (Valid() && enumeratedData.back().empty())
            enumeratedData.pop_back();
    }
    bool CurrentPositionNoMatchFileSpec() const
    {
        return !enumeratedData.empty() && !PathMatchSpecW(enumeratedData.back().front().GetFileName().c_str(), fileSpec.c_str());
    }
public:
    BasicRecursiveEnumeration() {};
    BasicRecursiveEnumeration(const std::wstring& pathSpec) {
        std::wstring::const_iterator lastSlash = GetLastSlash(pathSpec);
        if (lastSlash == pathSpec.begin()) {
            fileSpec = pathSpec;
            EnumerateDirectory(L"*");
        } else {
            fileSpec.assign(lastSlash, pathSpec.end());
            std::wstring firstQuery(pathSpec.begin(), lastSlash);
            firstQuery.push_back(L'*');
            EnumerateDirectory(firstQuery);
            while (CurrentPositionNoMatchFileSpec())
                PerformIncrement();
        }
    };
    void increment() {
        do
        {
            PerformIncrement();
        } while (CurrentPositionNoMatchFileSpec());
    };
    bool equal(const BasicRecursiveEnumeration<FindXFileFunctions_T>& other) const {
        if (!Valid())
            return !other.Valid();
        if (!other.Valid())
            return false;
        return this == &other;
    };
    Win32FindData dereference() const {
        return enumeratedData.back().front();
    };
    bool Valid() const {
        return !enumeratedData.empty();
    };
};

typedef BasicRecursiveEnumeration<RealFindXFileFunctions> RecursiveEnumeration;

struct AllResults
{
    bool operator()(const Win32FindData&) {
        return true;
    };
}; 

struct FilesOnly
{
    bool operator()(const Win32FindData& arg) {
        return arg.IsFile();
    };
};

template <typename Filter_T, typename Recurse_T>
class DirectoryIterator : 
    public boost::iterator_facade<
        DirectoryIterator<Filter_T, Recurse_T>,
        Win32FindData,
        std::input_iterator_tag,
        Win32FindData
    >
{
    friend class boost::iterator_core_access;
    boost::shared_ptr<Recurse_T> impl;
    Filter_T filter;
    void increment() {
        do {
            impl->increment();
        } while (impl->Valid() && !filter(impl->dereference()));
    };
    bool equal(const DirectoryIterator& other) const {
        return impl->equal(*other.impl);
    };
    Win32FindData dereference() const {
        return impl->dereference();
    };
public:
    DirectoryIterator(Filter_T functor = Filter_T()) :
        impl(boost::make_shared<Recurse_T>()),
        filter(functor) {
    };
    explicit DirectoryIterator(const std::wstring& pathSpec, Filter_T functor = Filter_T()) :
        impl(boost::make_shared<Recurse_T>(pathSpec)),
        filter(functor) {
    };
};

}}
Run Code Online (Sandbox Code Playgroud)

测试:

#include <queue>
#include "../WideCharacterOutput.hpp"
#include <boost/test/unit_test.hpp>
#include "../../WindowsAPI++/FileSystem/Enumerator.hpp"
using namespace WindowsAPI::FileSystem;


struct SimpleFakeFindXFileFunctions
{
    static std::deque<WIN32_FIND_DATAW> fakeData;
    static std::wstring insertedFileName;

    static HANDLE FindFirst(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) {
        insertedFileName.assign(lpFileName);
        if (fakeData.empty()) {
            SetLastError(ERROR_PATH_NOT_FOUND);
            return INVALID_HANDLE_VALUE;
        }
        *lpFindFileData = fakeData.front();
        fakeData.pop_front();
        return reinterpret_cast<HANDLE>(42);
    };
    static BOOL FindNext(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) {
        BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
        if (fakeData.empty()) {
            SetLastError(ERROR_NO_MORE_FILES);
            return 0;
        }
        *lpFindFileData = fakeData.front();
        fakeData.pop_front();
        return 1;
    };
    static BOOL Close(HANDLE hFindFile) {
        BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
        return 1;
    };

};

std::deque<WIN32_FIND_DATAW> SimpleFakeFindXFileFunctions::fakeData;
std::wstring SimpleFakeFindXFileFunctions::insertedFileName;

struct ErroneousFindXFileFunctionFirst
{
    static HANDLE FindFirst(LPCWSTR, LPWIN32_FIND_DATAW) {
        SetLastError(ERROR_ACCESS_DENIED);
        return INVALID_HANDLE_VALUE;
    };
    static BOOL FindNext(HANDLE hFindFile, LPWIN32_FIND_DATAW) {
        BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
        return 1;
    };
    static BOOL Close(HANDLE hFindFile) {
        BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
        return 1;
    };
};

struct ErroneousFindXFileFunctionNext
{
    static HANDLE FindFirst(LPCWSTR, LPWIN32_FIND_DATAW) {
        return reinterpret_cast<HANDLE>(42);
    };
    static  BOOL FindNext(HANDLE hFindFile, LPWIN32_FIND_DATAW) {
        BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    };
    static BOOL Close(HANDLE hFindFile) {
        BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
        return 1;
    };
};

struct DirectoryIteratorTestsFixture
{
    typedef SimpleFakeFindXFileFunctions fakeFunctor;
    DirectoryIteratorTestsFixture() {
        WIN32_FIND_DATAW test;
        wcscpy_s(test.cFileName, L".");
        wcscpy_s(test.cAlternateFileName, L".");
        test.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
        GetSystemTimeAsFileTime(&test.ftCreationTime);
        test.ftLastWriteTime = test.ftCreationTime;
        test.ftLastAccessTime = test.ftCreationTime;
        test.nFileSizeHigh = 0;
        test.nFileSizeLow = 0;
        fakeFunctor::fakeData.push_back(test);

        wcscpy_s(test.cFileName, L"..");
        wcscpy_s(test.cAlternateFileName, L"..");
        fakeFunctor::fakeData.push_back(test);

        wcscpy_s(test.cFileName, L"File.txt");
        wcscpy_s(test.cAlternateFileName, L"FILE.TXT");
        test.nFileSizeLow = 1024;
        test.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
        fakeFunctor::fakeData.push_back(test);

        wcscpy_s(test.cFileName, L"System32");
        wcscpy_s(test.cAlternateFileName, L"SYSTEM32");
        test.nFileSizeLow = 0;
        test.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
        fakeFunctor::fakeData.push_back(test);
    };
    ~DirectoryIteratorTestsFixture() {
        fakeFunctor::fakeData.clear();
    };
};

BOOST_FIXTURE_TEST_SUITE( DirectoryIteratorTests, DirectoryIteratorTestsFixture )

template<typename fakeFunctor>
static void NonRecursiveIteratorAssertions()
{
    typedef DirectoryIterator<AllResults
        ,BasicNonRecursiveEnumeration<SimpleFakeFindXFileFunctions> > testType;
    testType begin(L"C:\\Windows\\*");
    testType end;
    BOOST_CHECK_EQUAL(fakeFunctor::insertedFileName, L"C:\\Windows\\*");
    BOOST_CHECK(begin->GetFolderPath() == L"C:\\Windows");
    BOOST_CHECK(begin->GetFileName() == L"File.txt");
    BOOST_CHECK(begin->GetFullFileName() == L"C:\\Windows\\File.txt");
    BOOST_CHECK(begin->GetShortFileName() == L"FILE.TXT");
    BOOST_CHECK_EQUAL(begin->GetSize(), 1024);
    BOOST_CHECK(begin->IsFile());
    BOOST_CHECK(begin != end);
    begin++;
    BOOST_CHECK(begin->GetFileName() == L"System32");
    BOOST_CHECK(begin->GetFullFileName() == L"C:\\Windows\\System32");
    BOOST_CHECK(begin->GetShortFileName() == L"SYSTEM32");
    BOOST_CHECK_EQUAL(begin->GetSize(), 0);
    BOOST_CHECK(begin->IsDirectory());
    begin++;
    BOOST_CHECK(begin == end);
}

BOOST_AUTO_TEST_CASE( BasicEnumeration )
{
    NonRecursiveIteratorAssertions<fakeFunctor>();
}

BOOST_AUTO_TEST_CASE( NoRootDirectories )
{
    fakeFunctor::fakeData.pop_front();
    fakeFunctor::fakeData.pop_front();
    NonRecursiveIteratorAssertions<fakeFunctor>();
}

static void EmptyIteratorAssertions() {
    typedef DirectoryIterator<AllResults
        ,BasicNonRecursiveEnumeration<SimpleFakeFindXFileFunctions> > testType;
    testType begin(L"C:\\Windows\\*");
    testType end;
    BOOST_CHECK(begin == end);
}

BOOST_AUTO_TEST_CASE( Empty1 )
{
    fakeFunctor::fakeData.clear();
    EmptyIteratorAssertions();
}

BOOST_AUTO_TEST_CASE( Empty2 )
{
    fakeFunctor::fakeData.erase(fakeFunctor::fakeData.begin() + 2, fakeFunctor::fakeData.end());
    EmptyIteratorAssertions();
}

BOOST_AUTO_TEST_CASE( CorrectDestruction )
{
    typedef DirectoryIterator<AllResults
        ,BasicNonRecursiveEnumeration<SimpleFakeFindXFileFunctions> > testType;
    testType begin(L"C:\\Windows\\*");
    testType end;
}

BOOST_AUTO_TEST_CASE( Exceptions )
{
    typedef DirectoryIterator<AllResults,BasicNonRecursiveEnumeration<ErroneousFindXFileFunctionFirst> >
        firstFailType;
    BOOST_CHECK_THROW(firstFailType(L"C:\\Windows\\*"), WindowsAPI::ErrorAccessDeniedException);
    typedef DirectoryIterator<AllResults,BasicNonRecursiveEnumeration<ErroneousFindXFileFunctionNext> >
        nextFailType;
    nextFailType constructedOkay(L"C:\\Windows\\*");
    BOOST_CHECK_THROW(constructedOkay++, WindowsAPI::ErrorInvalidParameterException);
}

BOOST_AUTO_TEST_SUITE_END()

struct RecursiveFakeFindXFileFunctions
{
    static std::deque<std::pair<std::deque<WIN32_FIND_DATA> , std::wstring> >  fakeData;
    static std::size_t openHandles;
    static HANDLE FindFirst(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) {
        BOOST_REQUIRE(!fakeData.empty());
        BOOST_REQUIRE_EQUAL(lpFileName, fakeData.front().second);
        openHandles++;
        BOOST_REQUIRE_EQUAL(openHandles, 1);
        if (fakeData.front().first.empty()) {
            openHandles--;
            SetLastError(ERROR_PATH_NOT_FOUND);
            return INVALID_HANDLE_VALUE;
        }
        *lpFindFileData = fakeData.front().first.front();
        fakeData.front().first.pop_front();
        return reinterpret_cast<HANDLE>(42);
    };
    static BOOL FindNext(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) {
        BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
        if (fakeData.front().first.empty()) {
            SetLastError(ERROR_NO_MORE_FILES);
            return 0;
        }
        *lpFindFileData = fakeData.front().first.front();
        fakeData.front().first.pop_front();
        return 1;
    };
    static BOOL Close(HANDLE hFindFile) {
        BOOST_CHECK_EQUAL(reinterpret_cast<HANDLE>(42), hFindFile);
        openHandles--;
        BOOST_REQUIRE_EQUAL(openHandles, 0);
        fakeData.pop_front();
        return 1;
    };
};

std::deque<std::pair<std::deque<WIN32_FIND_DATA> , std::wstring> > RecursiveFakeFindXFileFunctions::fakeData;
std::size_t RecursiveFakeFindXFileFunctions::openHandles;

struct RecursiveDirectoryFixture
{
    RecursiveDirectoryFixture() {
        WIN32_FIND_DATAW tempData;
        ZeroMemory(&tempData, sizeof(tempData));
        std::deque<WIN32_FIND_DATAW> dequeData;

        wcscpy_s(tempData.cFileName, L".");
        wcscpy_s(tempData.cAlternateFileName, L".");
        tempData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
        GetSystemTimeAsFileTime(&tempData.ftCreationTime);
        tempData.ftLastWriteTime = tempData.ftCreationTime;
        tempData.ftLastAccessTime = tempData.ftCreationTime;
        dequeData.push_back(tempData);

        wcscpy_s(tempData.cFileName, L"..");
        wcscpy_s(tempData.cAlternateFileName, L"..");
        dequeData.push_back(tempData);

        wcscpy_s(tempData.cFileName, L"MySubDirectory");
        wcscpy_s(tempData.cAlternateFileName, L"MYSUBD~1");
        dequeData.push_back(tempData);

        wcscpy_s(tempData.cFileName, L"MyFile.txt");
        wcscpy_s(tempData.cAlternateFileName, L"MYFILE.TXT");
        tempData.nFileSizeLow = 500;
        tempData.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
        dequeData.push_back(tempData);

        RecursiveFakeFindXFileFunctions::fakeData.push_back
            (std::make_pair(dequeData, L"C:\\Windows\\*"));

        dequeData.clear();

        wcscpy_s(tempData.cFileName, L".");
        wcscpy_s(tempData.cAlternateFileName, L".");
        tempData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
        GetSystemTimeAsFileTime(&tempData.ftCreationTime);
        tempData.ftLastWriteTime = tempData.ftCreationTime;
        tempData.ftLastAccessTime = tempData.ftCreationTime;
        dequeData.push_back(tempData);

        wcscpy_s(tempData.cFileName, L"..");
        wcscpy_s(tempData.cAlternateFileName, L"..");
        dequeData.push_back(tempData);

        wcscpy_s(tempData.cFileName, L"MyFile2.txt");
        wcscpy_s(tempData.cAlternateFileName, L"NYFILE2.TXT");
        tempData.nFileSizeLow = 1024;
        tempData.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
        dequeData.push_back(tempData);

        RecursiveFakeFindXFileFunctions::fakeData.push_back
            (std::make_pair(dequeData, L"C:\\Windows\\MySubDirectory\\*"));
    };
    ~RecursiveDirectoryFixture() {
        RecursiveFakeFindXFileFunctions::fakeData.clear();
    };
};

BOOST_AUTO_TEST_SUITE( RecursiveDirectoryIteratorTests )

BOOST_AUTO_TEST_CASE( BasicEnumerationTxt )
{
    RecursiveDirectoryFixture DataFixture;
    typedef DirectoryIterator<AllResults
        ,BasicRecursiveEnumeration<RecursiveFakeFindXFileFunctions> > testType;
    testType begin(L"C:\\Windows\\*.txt");
    testType end;

    BOOST_CHECK(begin->IsFile());
    BOOST_CHECK_EQUAL(begin->GetSize(), 1024);
    BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows\\MySubDirectory");
    BOOST_CHECK_EQUAL(begin->GetFileName(), L"MyFile2.txt");
    BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MySubDirectory\\MyFile2.txt");
    BOOST_CHECK(begin != end);

    begin++;

    BOOST_CHECK(begin->IsFile());
    BOOST_CHECK_EQUAL(begin->GetSize(), 500);
    BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows");
    BOOST_CHECK_EQUAL(begin->GetFileName(), L"MyFile.txt");
    BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MyFile.txt");
    BOOST_CHECK(begin != end);

    begin++;

    BOOST_CHECK(begin == end);
}

BOOST_AUTO_TEST_CASE( BasicEnumerationAll )
{
    RecursiveDirectoryFixture DataFixture;
    typedef DirectoryIterator<AllResults
        ,BasicRecursiveEnumeration<RecursiveFakeFindXFileFunctions> > testType;
    testType begin(L"C:\\Windows\\*");
    testType end;

    BOOST_CHECK(begin->IsDirectory());
    BOOST_CHECK_EQUAL(begin->GetSize(), 0);
    BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows");
    BOOST_CHECK_EQUAL(begin->GetFileName(), L"MySubDirectory");
    BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MySubDirectory");
    BOOST_CHECK(begin != end);

    begin++;

    BOOST_CHECK(begin->IsFile());
    BOOST_CHECK_EQUAL(begin->GetSize(), 1024);
    BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows\\MySubDirectory");
    BOOST_CHECK_EQUAL(begin->GetFileName(), L"MyFile2.txt");
    BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MySubDirectory\\MyFile2.txt");
    BOOST_CHECK(begin != end);

    begin++;

    BOOST_CHECK(begin->IsFile());
    BOOST_CHECK_EQUAL(begin->GetSize(), 500);
    BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows");
    BOOST_CHECK_EQUAL(begin->GetFileName(), L"MyFile.txt");
    BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MyFile.txt");
    BOOST_CHECK(begin != end);

    begin++;

    BOOST_CHECK(begin == end);
}

BOOST_AUTO_TEST_CASE( RecursionOrderMaintained )
{
    WIN32_FIND_DATAW tempData;
    ZeroMemory(&tempData, sizeof(tempData));
    std::deque<WIN32_FIND_DATAW> dequeData;

    wcscpy_s(tempData.cFileName, L".");
    wcscpy_s(tempData.cAlternateFileName, L".");
    tempData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
    GetSystemTimeAsFileTime(&tempData.ftCreationTime);
    tempData.ftLastWriteTime = tempData.ftCreationTime;
    tempData.ftLastAccessTime = tempData.ftCreationTime;
    dequeData.push_back(tempData);

    wcscpy_s(tempData.cFileName, L"..");
    wcscpy_s(tempData.cAlternateFileName, L"..");
    dequeData.push_back(tempData);

    wcscpy_s(tempData.cFileName, L"MySubDirectory");
    wcscpy_s(tempData.cAlternateFileName, L"MYSUBD~1");
    dequeData.push_back(tempData);

    wcscpy_s(tempData.cFileName, L"MyFile.txt");
    wcscpy_s(tempData.cAlternateFileName, L"MYFILE.TXT");
    tempData.nFileSizeLow = 500;
    tempData.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
    dequeData.push_back(tempData);

    wcscpy_s(tempData.cFileName, L"Zach");
    wcscpy_s(tempData.cAlternateFileName, L"ZACH");
    tempData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
    tempData.nFileSizeLow = 0;
    dequeData.push_back(tempData);

    RecursiveFakeFindXFileFunctions::fakeData.push_back
        (std::make_pair(dequeData, L"C:\\Windows\\*"));

    dequeData.clear();

    wcscpy_s(tempData.cFileName, L".");
    wcscpy_s(tempData.cAlternateFileName, L".");
    tempData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
    GetSystemTimeAsFileTime(&tempData.ftCreationTime);
    tempData.ftLastWriteTime = tempData.ftCreationTime;
    tempData.ftLastAccessTime = tempData.ftCreationTime;
    dequeData.push_back(tempData);

    wcscpy_s(tempData.cFileName, L"..");
    wcscpy_s(tempData.cAlternateFileName, L"..");
    dequeData.push_back(tempData);

    wcscpy_s(tempData.cFileName, L"MyFile2.txt");
    wcscpy_s(tempData.cAlternateFileName, L"NYFILE2.TXT");
    tempData.nFileSizeLow = 1024;
    tempData.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
    dequeData.push_back(tempData);

    RecursiveFakeFindXFileFunctions::fakeData.push_back
        (std::make_pair(dequeData, L"C:\\Windows\\MySubDirectory\\*"));

    dequeData.clear();
    wcscpy_s(tempData.cFileName, L".");
    wcscpy_s(tempData.cAlternateFileName, L".");
    tempData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
    GetSystemTimeAsFileTime(&tempData.ftCreationTime);
    tempData.ftLastWriteTime = tempData.ftCreationTime;
    tempData.ftLastAccessTime = tempData.ftCreationTime;
    dequeData.push_back(tempData);

    wcscpy_s(tempData.cFileName, L"..");
    wcscpy_s(tempData.cAlternateFileName, L"..");
    dequeData.push_back(tempData);

    wcscpy_s(tempData.cFileName, L"ZachFile.txt");
    wcscpy_s(tempData.cAlternateFileName, L"ZACHFILE.TXT");
    tempData.nFileSizeLow = 1024;
    tempData.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
    dequeData.push_back(tempData);

    RecursiveFakeFindXFileFunctions::fakeData.push_back
        (std::make_pair(dequeData, L"C:\\Windows\\Zach\\*"));

    typedef DirectoryIterator<AllResults
        ,BasicRecursiveEnumeration<RecursiveFakeFindXFileFunctions> > testType;
    testType begin(L"C:\\Windows\\*");
    testType end;

    BOOST_CHECK(begin->IsDirectory());
    BOOST_CHECK_EQUAL(begin->GetSize(), 0);
    BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows");
    BOOST_CHECK_EQUAL(begin->GetFileName(), L"MySubDirectory");
    BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MySubDirectory");
    BOOST_CHECK(begin != end);

    begin++;

    BOOST_CHECK(begin->IsFile());
    BOOST_CHECK_EQUAL(begin->GetSize(), 1024);
    BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows\\MySubDirectory");
    BOOST_CHECK_EQUAL(begin->GetFileName(), L"MyFile2.txt");
    BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MySubDirectory\\MyFile2.txt");
    BOOST_CHECK(begin != end);

    begin++;

    BOOST_CHECK(begin->IsFile());
    BOOST_CHECK_EQUAL(begin->GetSize(), 500);
    BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows");
    BOOST_CHECK_EQUAL(begin->GetFileName(), L"MyFile.txt");
    BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\MyFile.txt");
    BOOST_CHECK(begin != end);

    begin++;

    BOOST_CHECK(begin->IsDirectory());
    BOOST_CHECK_EQUAL(begin->GetSize(), 0);
    BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows");
    BOOST_CHECK_EQUAL(begin->GetFileName(), L"Zach");
    BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\Zach");
    BOOST_CHECK(begin != end);

    begin++;

    BOOST_CHECK(begin->IsFile());
    BOOST_CHECK_EQUAL(begin->GetSize(), 1024);
    BOOST_CHECK_EQUAL(begin->GetFolderPath(), L"C:\\Windows\\Zach");
    BOOST_CHECK_EQUAL(begin->GetFileName(), L"ZachFile.txt");
    BOOST_CHECK_EQUAL(begin->GetFullFileName(), L"C:\\Windows\\Zach\\ZachFile.txt");
    BOOST_CHECK(begin != end);

    begin++;

    BOOST_CHECK(begin == end);
}

BOOST_AUTO_TEST_CASE( Exceptions )
{
    typedef DirectoryIterator<AllResults,BasicRecursiveEnumeration<ErroneousFindXFileFunctionFirst> >
        firstFailType;
    BOOST_CHECK_THROW(firstFailType(L"C:\\Windows\\*"), WindowsAPI::ErrorAccessDeniedException);
    typedef DirectoryIterator<AllResults,BasicRecursiveEnumeration<ErroneousFindXFileFunctionNext> >
        nextFailType;
    BOOST_CHECK_THROW(nextFailType(L"C:\\Windows\\*"), WindowsAPI::ErrorInvalidParameterException);
}

BOOST_AUTO_TEST_SUITE_END()
Run Code Online (Sandbox Code Playgroud)

Jam*_*lis 5

要解决第一个问题,可以end()返回一些sentinel值,然后在迭代器的递增函数中,将迭代器设置为等于该容器末尾的sentinel值.这实际上是Boost.Filesystem中目录迭代器的作用.

对于第二个问题,我并不完全熟悉FindXFileAPI,但是一个选项是返回一些包含所需数据的结构,或者包含成员函数的结构,以获取您可能需要的每个数据.