34

我找不到任何现成的东西,所以我想出了:

class membuf : public basic_streambuf<char>
{
public:
  membuf(char* p, size_t n) {
    setg(p, p, p + n);
    setp(p, p + n);
  }
}

用法:

char *mybuffer;
size_t length;
// ... allocate "mybuffer", put data into it, set "length"

membuf mb(mybuffer, length);
istream reader(&mb);
// use "reader"

我知道stringstream,但它似乎无法处理给定长度的二进制数据。

我在这里发明自己的轮子吗?

编辑

  • 不能复制输入数据,只需创建将迭代数据的东西。
  • 它必须是可移植的——至少它应该可以在 gcc 和 MSVC 下工作。
4

4 回答 4

31

我假设您的输入数据是二进制的(不是文本),并且您想从中提取大块的二进制数据。所有这些都无需复制您的输入数据。

您可以将boost::iostreams::basic_array_sourceand boost::iostreams::stream_buffer(来自Boost.Iostreams)与boost::archive::binary_iarchive(来自Boost.Serialization)结合起来,以便能够使用方便的提取 >> 运算符来读取二进制数据块。

#include <stdint.h>
#include <iostream>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/archive/binary_iarchive.hpp>

int main()
{
    uint16_t data[] = {1234, 5678};
    char* dataPtr = (char*)&data;

    typedef boost::iostreams::basic_array_source<char> Device;
    boost::iostreams::stream_buffer<Device> buffer(dataPtr, sizeof(data));
    boost::archive::binary_iarchive archive(buffer, boost::archive::no_header);

    uint16_t word1, word2;
    archive >> word1 >> word2;
    std::cout << word1 << "," << word2 << std::endl;
    return 0;
}

使用 AMD64 上的 GCC 4.4.1,它输出:

1234,5678

Boost.Serialization 非常强大,知道如何序列化所有基本类型、字符串,甚至 STL 容器。您可以轻松地使您的类型可序列化。请参阅文档。隐藏在 Boost.Serialization 源代码中的某个地方是一个可移植二进制存档的示例,它知道如何为您的机器的字节序执行正确的交换。这也可能对您有用。

如果您不需要 Boost.Serialization 的花哨并且乐于以 fread() 类型的方式读取二进制数据,则可以basic_array_source以更简单的方式使用:

#include <stdint.h>
#include <iostream>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>

int main()
{
    uint16_t data[] = {1234, 5678};
    char* dataPtr = (char*)&data;

    typedef boost::iostreams::basic_array_source<char> Device;
    boost::iostreams::stream<Device> stream(dataPtr, sizeof(data));

    uint16_t word1, word2;
    stream.read((char*)&word1, sizeof(word1));
    stream.read((char*)&word2, sizeof(word2));
    std::cout << word1 << "," << word2 << std::endl;

    return 0;
}

我用这个程序得到了相同的输出。

于 2010-01-17T05:20:49.243 回答
5

我不确定您需要什么,但这是否符合您的要求?

char *mybuffer;
size_t length;
// allocate, fill, set length, as before

std::string data(mybuffer, length);
std::istringstream mb(data);
//use mb
于 2010-01-17T04:22:32.270 回答
4

标准流缓冲区具有此功能。
创建一个流。获取它的缓冲区然后覆盖它。

#include <sstream>
#include <iostream>
#include <algorithm>
#include <iterator>

int main()
{
    // Your imaginary buffer
    char    buffer[]    = "A large buffer we don't want to copy but use in a stream";

    // An ordinary stream.
    std::stringstream   str;

    // Get the streams buffer object. Reset the actual buffer being used.
    str.rdbuf()->pubsetbuf(buffer,sizeof(buffer));

    std::copy(std::istreambuf_iterator<char>(str),
              std::istreambuf_iterator<char>(),
              std::ostream_iterator<char>(std::cout)
             );
}
于 2010-01-17T05:17:51.160 回答
2

提问者想要一些不复制数据的东西,他的解决方案运行良好。我的贡献是稍微清理一下,这样您就可以创建一个对象,它是内存中数据的输入流。我已经对此进行了测试,并且可以正常工作。

class MemoryInputStream: public std::istream
    {
    public:
    MemoryInputStream(const uint8_t* aData,size_t aLength):
        std::istream(&m_buffer),
        m_buffer(aData,aLength)
        {
        rdbuf(&m_buffer); // reset the buffer after it has been properly constructed
        }

    private:
    class MemoryBuffer: public std::basic_streambuf<char>
        {
        public:
        MemoryBuffer(const uint8_t* aData,size_t aLength)
            {
            setg((char*)aData,(char*)aData,(char*)aData + aLength);
            }
        };

    MemoryBuffer m_buffer;
    };
于 2012-05-16T09:18:32.773 回答