如何为自定义 istream/streambuf 实现 seekg()? [英] How do I implement seekg() for a custom istream/streambuf?

查看:41
本文介绍了如何为自定义 istream/streambuf 实现 seekg()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I used to be a C++ expert a decade ago, but for the past 10 years I've been programming Java. I just started a C++ project that uses a small third-party XML parser. The XML parser accepts an STL istream. My XML data is coming from a Windows COM IStream. I thought I'd do the Right Thing and create an adapter to take the IStream data and present it to the XML parser through an istream.

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

I followed the excellent tutorial at http://www.mr-edd.co.uk/blog/beginners_guide_streambuf and created a COMStreambuf that takes data from the underlying COM IStream, and used it as a buffer for a custom COMIstream. Everything looks good, but I get a read error from the parser.

结果是解析器通过在 istream 上使用 seekg() 将整个文件读入内存以找出其大小,然后使用 seekg() 返回到开头一次性读取它.不出所料,上述教程决定为另一个帖子保存[实现搜索的说明]",但显然从未写过.

Turns out the parser reads the whole file into memory by using seekg() on the istream to find out its size and then goes back to the beginning with seekg() to read it in one go. Unsurprisingly, the aforementioned tutorial decided to "save [instructions on implementing seeking] for another post" which was apparently never written.

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

Can someone tell me what I need to do to implement seekg() with my custom istream/streambuf? I would venture out doing it myself (my first inclination would be to override stuff in istream), but with my inexperience this deep in the STL and with my Java mentality I fear I would do something incomplete and have a brittle solution. (Without reading tutorials, for example, I never would have guessed that one makes a custom istream by writing a new streambuf, for example, or that I would need to call imbue() with a default locale, etc.)

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

Thanks for any help. I've been very impressed with this site---both with the knowledge of the participants and their friendly, honest nature in conceding who has the best answer. :)

推荐答案

我认为seekg"是指 seekoffseekpos.

实现COMStreambuf 成员seekoffseekpos 的直接方法是包装Seek IStream 接口的方法.例如,这样的事情应该有效:

The straightforward way to implement members seekoff and seekpos of your COMStreambuf is to wrap the Seek method of the IStream interface. For example, something like this should work:

// 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 的位置后,我调用:

In this listing, after setting the position of streamIn I call:

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

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

After a seek, sputbackc or sungetc will operate on old data. You may want to consider whether this makes sense for your application and do something different.

这篇关于如何为自定义 istream/streambuf 实现 seekg()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆