C ++-从字符获取istream *

我有一个char *和从库中接收到的数据长度,我需要将数据传递给采用istream的函数。

我知道我可以创建一个字符串流,但是它将复制所有数据。 而且,由于它是一个zip文件,因此数据肯定会为0,而创建stringstream会将数据一直存储到我认为的第一个0。

有什么方法可以从char *创建一个istream,它的大小无需复制所有数据吗?

Damian asked 2020-01-19T22:31:29Z
7个解决方案
65 votes

这是在网络上发现的一种不建议使用的方法,您是否可以派生自己的std::streambuf类,但是却很简单,并且似乎可以正常工作:

#include <iostream>
#include <istream>
#include <streambuf>
#include <string>

struct membuf : std::streambuf
{
    membuf(char* begin, char* end) {
        this->setg(begin, begin, end);
    }
};

int main()
{
    char buffer[] = "I'm a buffer with embedded nulls\0and line\n feeds";

    membuf sbuf(buffer, buffer + sizeof(buffer));
    std::istream in(&sbuf);
    std::string line;
    while (std::getline(in, line)) {
        std::cout << "line: " << line << "\n";
    }
    return 0;
}

哪个输出:

line: I'm a buffer with embedded nullsand line
line:  feeds
HostileFork answered 2020-01-19T22:31:42Z
12 votes

使用Boost的不建议使用的解决方案:

#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/array.hpp>
using namespace boost::iostreams;

basic_array_source<char> input_source(my_ptr_to_char, byte_count);
stream<basic_array_source<char> > input_stream(input_source);

甚至更简单:

#include <boost/interprocess/streams/bufferstream.hpp>
using namespace boost::interprocess;

bufferstream input_stream(my_ptr_to_char, byte_count);
ZunTzu answered 2020-01-19T22:32:06Z
7 votes

我需要一个支持tellgchar_array_buffer且不需要增强的解决方案。

编写自定义流缓冲区(std :: streambuf)的新手指南中的char_array_buffer提供了一个起点。

byte_array_buffer.h:

#include <cstdio>
#include <string>
#include <list>
#include <fstream>
#include <iostream>

//
// http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
//

class byte_array_buffer : public std::streambuf
{
public:
    byte_array_buffer(const uint8_t *begin, const size_t size);

private:
    int_type underflow();
    int_type uflow();
    int_type pbackfail(int_type ch);
    std::streamsize showmanyc();
    std::streampos seekoff ( std::streamoff off, std::ios_base::seekdir way,
                            std::ios_base::openmode which = std::ios_base::in | std::ios_base::out );
    std::streampos seekpos ( std::streampos sp,
                            std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);

    // copy ctor and assignment not implemented;
    // copying not allowed
    byte_array_buffer(const byte_array_buffer &);
    byte_array_buffer &operator= (const byte_array_buffer &);

private:
    const uint8_t * const begin_;
    const uint8_t * const end_;
    const uint8_t * current_;
};

byte_array_buffer.cpp:

#include "byte_array_buffer.h"

#include <cassert>


byte_array_buffer::byte_array_buffer(const uint8_t *begin, const size_t size) :
begin_(begin),
end_(begin + size),
current_(begin_)
{
    assert(std::less_equal<const uint8_t *>()(begin_, end_));
}

byte_array_buffer::int_type byte_array_buffer::underflow()
{
    if (current_ == end_)
        return traits_type::eof();

    return traits_type::to_int_type(*current_);
}

byte_array_buffer::int_type byte_array_buffer::uflow()
{
    if (current_ == end_)
        return traits_type::eof();

    return traits_type::to_int_type(*current_++);
}

byte_array_buffer::int_type byte_array_buffer::pbackfail(int_type ch)
{
    if (current_ == begin_ || (ch != traits_type::eof() && ch != current_[-1]))
        return traits_type::eof();

    return traits_type::to_int_type(*--current_);
}

std::streamsize byte_array_buffer::showmanyc()
{
    assert(std::less_equal<const uint8_t *>()(current_, end_));
    return end_ - current_;
}


std::streampos byte_array_buffer::seekoff ( std::streamoff off, std::ios_base::seekdir way,
                                           std::ios_base::openmode which )
{
    if (way == std::ios_base::beg)
    {
        current_ = begin_ + off;
    }
    else if (way == std::ios_base::cur)
    {
        current_ += off;
    }
    else if (way == std::ios_base::end)
    {
        current_ = end_ + off;
    }

    if (current_ < begin_ || current_ > end_)
        return -1;


    return current_ - begin_;
}

std::streampos byte_array_buffer::seekpos ( std::streampos sp,
                                           std::ios_base::openmode which )
{
    current_ = begin_ + sp;

    if (current_ < begin_ || current_ > end_)
        return -1;

    return current_ - begin_;
}
catlan answered 2020-01-19T22:32:39Z
6 votes

唯一(简单)可移植的方法包括制作副本:

std::istringstream ss(std::string(buf,len));

实际上,这可能会将数据复制两次,一次创建stringbuf,一次创建istringstream。(也许C ++ 11可以通过move构造函数避免复制其中之一;我不确定。)

但是,如果幸运的话,您的C ++实现将允许您执行以下操作:

std::istringstream ss;
ss.rdbuf()->pubsetbuf(buf,len);

在GNU C ++(以及我相信还有其他一些实现)下,这将创建字符串流而不复制数据。 但这是根据规范的“实现定义”行为。 (另请参阅此问题。)

通过包含stringbuf参数,可以确保这两个参数都不会出现空字符问题。

执行所需操作的唯一可移植方法是实现自己的stringbuf子类,并使用它来初始化字符串流。 不是为了胆小的人。

Nemo answered 2020-01-19T22:33:23Z
1 votes

您是否尝试过std :: istrstream?[http://stdcxx.apache.org/doc/stdlibref/istrstream.html]

从技术上讲,我认为它已过时,但仍是标准的一部分。

jeffrey_t_b answered 2020-01-19T22:33:47Z
0 votes

对接受的答案的扩展,它支持tellg和seekg:

struct membuf : std::streambuf
{
    membuf(char* begin, char* end)
    {
        this->setg(begin, begin, end);
    }

    pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which = std::ios_base::in) override
    {
        if (dir == std::ios_base::cur)
            gbump(off);
        else if (dir == std::ios_base::end)
            setg(eback(), egptr() + off, egptr());
        else if (dir == std::ios_base::beg)
            setg(eback(), eback() + off, egptr());
        return gptr() - eback();
    }

    pos_type seekpos(pos_type sp, std::ios_base::openmode which) override
    {
        return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which);
    }
};

该类的用法保持不变。

Vincent Wen answered 2020-01-19T22:34:11Z
-1 votes

尝试使用Boost.Iostreams数组源和接收器类。

[http://www.boost.org/doc/libs/1_47_0/libs/iostreams/doc/index.html]

Benjamin Lindley answered 2020-01-19T22:34:35Z
translate from https://stackoverflow.com:/questions/7781898/get-an-istream-from-a-char