Скопируйте содержимое потокового буфера в строку - PullRequest
31 голосов
/ 18 мая 2009

Очевидно, boost::asio::async_read не любит строки, так как единственная перегрузка boost::asio::buffer позволяет мне создавать const_buffer s, поэтому я застрял с чтением всего в streambuf. * ​​1004 * Теперь я хочу скопировать содержимое streambuf в строку, но, очевидно, он поддерживает только запись в char * (sgetn()), создание istream с помощью streambuf и использование getline().

Есть ли другой способ создать строку с содержимым streambufs без чрезмерного копирования?

Ответы [ 9 ]

45 голосов
/ 18 мая 2009

Я не знаю, считается ли это " чрезмерным копированием ", но вы можете использовать поток строк:

std::ostringstream ss;
ss << someStreamBuf;
std::string s = ss.str();

Например, чтобы прочитать все из стандартного ввода в строку, выполните

std::ostringstream ss;
ss << std::cin.rdbuf();
std::string s = ss.str();

В качестве альтернативы вы также можете использовать istreambuf_iterator. Вы должны будете измерить, является ли этот или вышеупомянутый способ более быстрым - я не знаю.

std::string s((istreambuf_iterator<char>(someStreamBuf)), 
               istreambuf_iterator<char>());

Обратите внимание, что someStreamBuf выше означает streambuf*, поэтому примите его адрес соответствующим образом. Также обратите внимание на дополнительные скобки вокруг первого аргумента в последнем примере, чтобы он не интерпретировался как объявление функции, возвращающей строку и принимающей итератор и другой указатель на функцию («самый неприятный анализ»).

37 голосов
/ 08 декабря 2012

Это действительно похоронен в документах ...

Дано boost::asio::streambuf b, с size_t buf_size ...

boost::asio::streambuf::const_buffers_type bufs = b.data();
std::string str(boost::asio::buffers_begin(bufs),
                boost::asio::buffers_begin(bufs) + buf_size);
24 голосов
/ 19 мая 2009

Другая возможность с boost::asio::streambuf заключается в использовании boost::asio::buffer_cast<const char*>() в сочетании с boost::asio::streambuf::data() и boost::asio::streambuf::consume() следующим образом:

const char* header=boost::asio::buffer_cast<const char*>(readbuffer.data());
//Do stuff with header, maybe construct a std::string with std::string(header,header+length)
readbuffer.consume(length);

Это не будет работать с обычными потоковыми буферами и может считаться грязным, но, похоже, это самый быстрый способ сделать это.

13 голосов
/ 17 октября 2012

Для boost::asio::streambuf вы можете найти решение, подобное этому:

    boost::asio::streambuf buf;
    /*put data into buf*/

    std::istream is(&buf);
    std::string line;
    std::getline(is, line);

Распечатать строку:

    std::cout << line << std::endl;

Вы можете найти здесь: http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/async_read_until/overload3.html

1 голос
/ 01 июля 2013

Также можно получить символы из asio::streambuf, используя std::basic_streambuf::sgetn:

asio::streambuf in;
// ...
char cbuf[in.size()+1]; int rc = in.sgetn (cbuf, sizeof cbuf); cbuf[rc] = 0;
std::string str (cbuf, rc);
0 голосов
/ 11 ноября 2016

Более простым ответом было бы преобразовать его в std::string и манипулировать им, что-то вроде этого

 std::string buffer_to_string(const boost::asio::streambuf &buffer)
 {
  using boost::asio::buffers_begin;
  auto bufs = buffer.data();
  std::string result(buffers_begin(bufs), buffers_begin(bufs) + buffer.size());
 return result;
}

Предоставление очень краткого кода для задания.

0 голосов
/ 24 июня 2016

Я протестировал первый ответ и получил ошибку компилятора при компиляции с использованием "g ++ -std = c ++ 11" То, что работало для меня, было:

        #include <string>
        #include <boost/asio.hpp>
        #include <sstream>           
        //other code ...
        boost::asio::streambuf response;
        //more code
        std::ostringstream sline;
        sline << &response; //need '&' or you a compiler error
        std::string line = sline.str(); 

Это скомпилировано и запущено.

0 голосов
/ 12 июня 2009

Причина, по которой вы можете создать const_buffer только из std :: string, заключается в том, что std :: string явно не поддерживает прямую запись на основе указателя в своем контракте. Вы можете сделать что-то плохое, например, изменить размер вашей строки до определенного размера, затем const_cast constness из c_str () и обращаться с ним как с сырым буфером char *, но это очень непослушно и однажды доставит вам неприятности.

Я использую std :: vector для своих буферов, потому что, пока вектор не изменяет размер (или вы осторожны с изменением размера), вы можете делать прямую запись указателя просто отлично. Если мне нужны некоторые данные в виде std :: string, я должен их скопировать, но, как я поступаю с моими буферами чтения, все, что должно длиться дольше, чем обратный вызов чтения, должно быть скопировано независимо.

0 голосов
/ 18 мая 2009

Я думаю, что это больше похоже на:


streambuf.commit( number_of_bytes_read );

istream istr( &streambuf );
string s;
istr >> s;

Я не изучал код basic_streambuf, но я считаю, что это должна быть только одна копия в строке.

...