从(char*,size_t)创建C++内存流的简单方法,而不复制数据?

Mar*_*ski 29 c++ memorystream

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

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

用法:

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

membuf mb(mybuffer, length);
istream reader(&mb);
// use "reader"
Run Code Online (Sandbox Code Playgroud)

我知道stringstream,但它似乎无法使用给定长度的二进制数据.

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

编辑

  • 不能复制输入数据,只需创建迭代数据的东西.
  • 它必须是便携式的 - 至少它应该在gcc和MSVC下工作.

Emi*_*ier 28

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

您可以结合boost::iostreams::basic_array_sourceboost::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;
}
Run Code Online (Sandbox Code Playgroud)

在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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我只是想表达对 Loki 的不同意见。`&lt;&lt;` 和 `&gt;&gt;` 运算符在用于其他数据类型时“不应该工作”相同。如果你朝那个方向前进,你将别无选择,只能得出结论,将它们用作“流运算符”的 iostreams 已被破坏,因为这不是 **bitshift 运算符**(是的,这是它们的真实名称)的方式工作。 (2认同)

crm*_*ore 5

我不确定你需要什么,但这样做你想要的吗?

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

std::string data(mybuffer, length);
std::istringstream mb(data);
//use mb
Run Code Online (Sandbox Code Playgroud)

  • 我不明白为什么会特别处理NUL字节.注意长度分别传递给std :: string构造函数. (3认同)
  • 不,这会将字符串截断为缓冲区中第一次出现的 0x00 字节。我特别需要创建一个固定长度的流,当我在内存中的已知位置拥有这些数据时,我可以从中读取二进制数据。 (2认同)
  • 你确定吗?采用(char*,size_t)的字符串构造函数不会将char*param视为c样式(以null结尾)的字符串.它使用你给它的长度. (2认同)
  • 是的,对不起,你是对的。我被 VS 调试器可视化工具误导了。它截断了 NUL 字符上的字符串。剩余的数据放入字符串中。 (2认同)
  • 虽然您的方法满足了我的需要,但它确实会产生将输入数据复制到“data”字符串中的副作用。我想避免这种情况。抱歉没有早点说清楚。 (2认同)