c++ - 如何为自定义 istream/streambuf 实现 seekg()?

标签 c++ xml istream streambuf seekg

十年前,我曾经是一名 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 上的优秀教程并创建了一个从底层 COM IStream 获取数据的 COMStreambuf,并将其用作自定义 COMIStream 的缓冲区。一切看起来都很好,但我从解析器中收到读取错误。

事实证明,解析器通过在 istream 上使用 seekg() 来找出其大小,然后返回到开头,使用 seekg() 一次性读取它,从而将整个文件读入内存。不出所料,前面提到的教程决定“将 [instructions on implementing seeking] 保存到另一篇文章”,这显然从未写过。

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

感谢您的帮助。这个网站给我留下了深刻的印象——无论是参与者的知识,还是他们在承认谁拥有最佳答案时的友好、诚实的本性。 :)

最佳答案

我假设“seekg”是指 seekoffseekpos .

实现 COMStreambuf 的成员 seekoffseekpos 的直接方法是包装 Seek IStream 接口(interface)的方法。例如,像这样的东西应该可以工作:

// 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_);
}

在此 list 中,在设置 streamIn 的位置后,我调用:

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

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

关于c++ - 如何为自定义 istream/streambuf 实现 seekg()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3488153/

相关文章:

html - 为什么DOM中Attr继承自Node?

C++用fstream替换二进制文件中的数据

c++ - 使用动态内存分配重载 istream 运算符

c++ - 指向 int 的指针。 C++

c++ - 如何以位字节序将数字转换为字节数组

c++ - C++中char的类型(被C++入门解释搞糊涂了)

c++ - 什么是 istream_view,什么时候使用?

c++ - Eclipse自动在main方法处加断点

ios - 如何在 iOS 中将 NSData 变量转换为 NSInteger 变量

java - EditText 在开始时具有永久缩进