从 (char*, size_t) 创建 C++ 内存流而不复制数据的更简单方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2079912/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Simpler way to create a C++ memorystream from (char*, size_t), without copying the data?
提问by Marcin Seredynski
I couldn't find anything ready-made, so I came up with:
我找不到现成的东西,所以我想出了:
class membuf : public basic_streambuf<char>
{
public:
membuf(char* p, size_t n) {
setg(p, p, p + n);
setp(p, p + n);
}
}
Usage:
用法:
char *mybuffer;
size_t length;
// ... allocate "mybuffer", put data into it, set "length"
membuf mb(mybuffer, length);
istream reader(&mb);
// use "reader"
I know of stringstream
, but it doesn't seem to be able to work with binary data of given length.
我知道stringstream
,但它似乎无法处理给定长度的二进制数据。
Am I inventing my own wheel here?
我在这里发明了自己的轮子吗?
EDIT
编辑
- It must notcopy the input data, just create something that will iterate over the data.
- It must be portable - at least it should work both under gcc and MSVC.
- 它不能复制输入数据,只需创建将迭代数据的东西。
- 它必须是可移植的——至少它应该可以在 gcc 和 MSVC 下工作。
采纳答案by Emile Cormier
I'm assuming that your input data is binary (not text), and that you want to extract chunks of binary data from it. All without making a copy of your input data.
我假设您的输入数据是二进制的(不是文本),并且您想从中提取大量的二进制数据。所有这些都无需复制您的输入数据。
You can combine boost::iostreams::basic_array_source
and boost::iostreams::stream_buffer
(from Boost.Iostreams) with boost::archive::binary_iarchive
(from Boost.Serialization) to be able to use convenient extraction >> operators to read chunks of binary data.
您可以将boost::iostreams::basic_array_source
and 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;
}
With GCC 4.4.1 on AMD64, it outputs:
使用 AMD64 上的 GCC 4.4.1,它输出:
1234,5678
1234,5678
Boost.Serialization is very powerful and knows how to serialize all basic types, strings, and even STL containers. You can easily make your types serializable. See the documentation. Hidden somewhere in the Boost.Serialization sources is an example of a portable binary archive that knows how to perform the proper swapping for your machine's endianness. This might be useful to you as well.
Boost.Serialization 非常强大,它知道如何序列化所有基本类型、字符串,甚至 STL 容器。您可以轻松地使您的类型可序列化。请参阅文档。隐藏在 Boost.Serialization 源代码中的某个地方是一个便携式二进制存档示例,它知道如何为您的机器的字节序执行正确的交换。这也可能对您有用。
If you don't need the fanciness of Boost.Serialization and are happy to read the binary data in an fread()-type fashion, you can use basic_array_source
in a simpler way:
如果您不需要 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;
}
I get the same output with this program.
我用这个程序得到了相同的输出。
回答by crmoore
I'm not sure what you need, but does this do what you want?
我不确定您需要什么,但这是否符合您的要求?
char *mybuffer;
size_t length;
// allocate, fill, set length, as before
std::string data(mybuffer, length);
std::istringstream mb(data);
//use mb
回答by Martin York
The standard stream buffer has this functionality.
Create a stream. Gets its buffer then over-ride it.
标准流缓冲区具有此功能。
创建一个流。获取它的缓冲区然后覆盖它。
#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)
);
}
回答by Graham Asher
The questioner wanted something that doesn't copy the data, and his solution works fine. My contribution is to clean it up a little, so you can just create a single object that's an input stream for data in memory. I have tested this and it works.
提问者想要一些不复制数据的东西,他的解决方案工作正常。我的贡献是稍微清理一下,这样你就可以创建一个单一的对象,它是内存中数据的输入流。我已经测试过这个并且它有效。
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;
};