从char *获取一个istream
我有一个char *和从库中接收的数据长度,我需要将数据传递给一个采用istream的函数。
我知道我可以创build一个stringstream,但会复制所有的数据。 而且,这些数据肯定是0,因为它是一个zip文件,创build一个stringstream会把数据直到我认为的第一个0。
有没有什么办法从一个char *创build一个istream,而且它的大小没有复制所有的数据?
这是在网上find的一个不被弃用的方法,你有派生自己的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
使用Boost的不被弃用的解决scheme:
#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);
唯一的(简单)便携式方式包括复制:
std::istringstream ss(std::string(buf,len));
实际上,这可能会复制两次数据,一次创buildstring
,一次创buildistringstream
。 (也许C ++ 11可以通过移动构造函数来避免其中一个副本;我不确定。)
但是,如果你幸运的话,你的C ++实现会让你这样做:
std::istringstream ss; ss.rdbuf()->pubsetbuf(buf,len);
在GNU C ++(和我相信,其他一些实现)下,这将创buildstringstream而不复制数据。 但是这是根据规范的“实现定义”行为。 (也见这个问题 。)
通过包含len
参数,可以确保这两个参数对于空字符都没有问题。
唯一可行的方法就是实现你自己的stringbuf
的子类并使用它来初始化stringstream。 不是为了心灵的隐隐。
我需要一个支持tellg
和seekg
的解决scheme,并且不需要提升。
char_array_buffer
从一个初学者的指南到编写一个自定义的stream缓冲区(std :: streambuf)给了一个起点。
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_; } 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_; }
你有没有试过std :: istrstream? http://stdcxx.apache.org/doc/stdlibref/istrstream.html
从技术上讲,我认为这是不合时宜的,但仍然是标准的一部分。
尝试Boost.Iostreams数组源和接收器类。
http://www.boost.org/doc/libs/1_47_0/libs/iostreams/doc/index.html