【问题标题】:How do I implement seekg() for a custom istream/streambuf?如何为自定义 istream/streambuf 实现 seekg()?
【发布时间】:2011-03-30 02:59:48
【问题描述】:

十年前我曾经是一名 C++ 专家,但在过去的 10 年里,我一直在编写 Java。我刚刚开始了一个使用小型第三方 XML 解析器的 C++ 项目。 XML 解析器接受 STL istream。我的 XML 数据来自 Windows COM IStream。我想我会做正确的事并创建一个适配器来获取 IStream 数据并通过 istream 将其呈现给 XML 解析器。

我按照http://www.mr-edd.co.uk/blog/beginners_guide_streambuf 上的优秀教程创建了一个 COMStreambuf,它从底层 COM IStream 获取数据,并将其用作自定义 COMIstream 的缓冲区。一切看起来都不错,但我从解析器收到了一个读取错误。

原来解析器通过在 istream 上使用 seekg() 将整个文件读入内存以找出它的大小,然后使用 seekg() 回到开头一次性读取它。不出所料,前面提到的教程决定“为另一个帖子保存[关于实现搜索的说明]”,这显然从未写过。

谁能告诉我我需要做什么来使用我的自定义 istream/streambuf 实现 seekg()?我自己会冒险去做(我的第一个倾向是覆盖 istream 中的东西),但是由于我对 STL 的经验不够深入,加上我的 Java 心态,我担心我会做一些不完整的事情并且有一个脆弱的解决方案。 (例如,如果不阅读教程,我永远不会猜到有人会通过编写新的 streambuf 来制作自定义 istream,或者我需要使用默认语言环境调用 imbue() 等)

感谢您的帮助。这个网站给我留下了深刻的印象——参与者的知识和他们友好、诚实的天性承认谁有最好的答案。 :)

【问题讨论】:

    标签: c++ xml istream streambuf seekg


    【解决方案1】:

    我假设“seekg”是指seekoffseekpos

    实现COMStreambuf 的成员seekoffseekpos 的直接方法是包装IStream 接口的Seek 方法。例如,这样的事情应该可以工作:

    // COMStreambuf.cpp
    COMStreambuf::pos_type COMStreambuf::seekoff(COMStreambuf::off_type off_, std::ios_base::seekdir way_, std::ios_base::openmode which_)
    {
        union {
            LARGE_INTEGER liMove;
            ULARGE_INTEGER uliMove;
        };
        liMove.QuadPart = off_;
    
        DWORD dwOrigin = STREAM_SEEK_SET;
        if (way_ == std::ios_base::cur) {
            dwOrigin = STREAM_SEEK_CUR;
        } else if (way_ == std::ios_base::end) {
            dwOrigin = STREAM_SEEK_END;
        } else {
            assert(way_ == std::ios_base::beg);
            dwOrigin = STREAM_SEEK_SET;
            uliMove.QuadPart = off_; 
        }
    
        ULARGE_INTEGER uliNewPosition;
        if (which_ & std::ios_base::in) {
            if (which_ & std::ios_base::out)
                return pos_type(off_type(-1));
            HRESULT hres = streamIn->Seek(liMove, dwOrigin, &uliNewPosition);
            if (hres != S_OK)
                return pos_type(off_type(-1));
    
            setg(eback(), egptr(), egptr());
        } else if (which_ & std::ios_base::out) {
            HRESULT hres = streamOut->Seek(liMove, dwOrigin, &uliNewPosition);
            if (hres != S_OK)
                return pos_type(off_type(-1));
    
            setp(pbase(), epptr(), epptr());
        } else {
            return pos_type(off_type(-1));
        }
    
        return pos_type(uliNewPosition.QuadPart);
    }
    
    COMStreambuf::pos_type COMStreambuf::seekpos(COMStreambuf::pos_type sp_, std::ios_base::openmode which_)
    {
        return seekoff(off_type(sp_), std::ios_base::beg, which_);
    }
    

    在这个列表中,设置streamIn的位置后我调用:

    setg(eback(), egptr(), egptr());
    

    搜索后,sputbackcsungetc 将对旧数据进行操作。您可能需要考虑这对您的应用程序是否有意义并做一些不同的事情。

    【讨论】:

    • gback() 是什么?你的意思是eback()
    • @0x499602D2:是的。感谢您发现这一点。
    猜你喜欢
    • 2016-05-06
    • 2011-10-09
    • 2020-10-24
    • 2014-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-29
    • 1970-01-01
    相关资源
    最近更新 更多