创建一个substreambuf来读取现有的istream

时间:2014-03-06 08:14:46

标签: c++ istream streambuf

我正在尝试创建一个自定义std::streambuf,它充当父流的子流。这是对this SO thread answer中概述的实施的改编。

在下面的示例中,我试图简单地读取流的前5个字符"Hello,"。但是,当我将ifstream.read()调用buffer时,缓冲区会被"ello, "填充,就像它被一个人关闭一样。

#include <iostream>
#include <sstream>

using namespace std;

int main()
{
    stringstream ss;

    ss << "Hello, World!";

    substreambuf asd(ss.rdbuf(), 0, 5);

    istream istream(&asd);

    char buffer[6] = { '\0' };
    istream.read(buffer, sizeof(buffer));

    cout << buffer << endl; //prints "ello, "
}

我是streambuf的新手,我觉得我在这里遗漏了一些明显的东西。任何帮助将不胜感激。

以下是substreambuf的定义:

#include <iostream>
#include <sstream>

namespace std
{
    struct substreambuf : public streambuf
    {
        explicit substreambuf(streambuf* sbuf, streampos pos, streampos len) :
        m_sbuf(sbuf),
        m_pos(pos),
        m_len(len),
        m_read(0)
        {
            m_sbuf->pubseekpos(pos);

            setbuf(nullptr, 0);
        }

    protected:
        int underflow()
        {
            if (m_read >= m_len)
            {
                return traits_type::eof();
            }

            return m_sbuf->sgetc();
        }

        int uflow()
        {
            if (m_read >= m_len)
            {
                return traits_type::eof();
            }

            m_read += 1;

            return m_sbuf->snextc();
        }

        streampos seekoff(streamoff off, ios_base::seekdir seekdir, ios_base::openmode openmode = ios_base::in | ios_base::out)
        {
            if (seekdir == ios_base::beg)
            {
                off += m_pos;
            }
            else if (seekdir == ios_base::cur)
            {
                off += m_pos + m_read;
            }
            else if (seekdir == ios_base::end)
            {
                off += m_pos + m_len;
            }

            return m_sbuf->pubseekpos(off, openmode) - m_pos;
        }

        streampos seekpos(streampos streampos, ios_base::openmode openmode = ios_base::in | ios_base::out)
        {
            streampos += m_pos;

            if (streampos > m_pos + m_len)
            {
                return -1;
            }

            return m_sbuf->pubseekpos(streampos, openmode) - m_pos;
        }

    private:
        streambuf* m_sbuf;
        streampos m_pos;
        streamsize m_len;
        streampos m_read;
    };
};

1 个答案:

答案 0 :(得分:1)

当我第一次看到代码时,我觉得这很奇怪。

int uflow()
{
    // ...
    return m_sbuf->snextc();
}

为什么他会返回snextc()的结果?为uflow()定义的策略是“返回下一个可用字符并将输入流推进一个字符”。如果调用snextc(),输入序列将被提前,然后它将返回下一个字符。结果是至少跳过1个字符。

正确的调用方法是 sbumpc() ,因为它会先缓存下一个字符 ,提前输入流,然后返回它。

return m_sbuf->sbumpc();

Here is a demo.