2009-05-18 7 views
28

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

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

ответ

42

Я не знаю, считает ли он, как «чрезмерного копирования», но вы можете использовать stringstream:

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*, поэтому принимать его адрес в зависимости от обстоятельств. Также обратите внимание на дополнительные круглые скобки вокруг первого аргумента в последнем примере, так что он не интерпретирует его как объявление функции, возвращающее строку и беря итератор и другой указатель на функцию («самый неприятный синтаксический анализ»).

+2

Спасибо, istreambuf_iterator был тем, что я искал. – tstenner

+1

Вот что-то странное. Я не могу предположить, почему, но istreambuf_iterator разрезает последние символы (если в последней строке больше 20 символов). Есть ли какие-нибудь идеи, почему это может быть? –

+0

ss << someStreamBuf копирует 11 байтов 0xFFFFFFFFF, которые представляют адрес streambuf в памяти. Благодарю. очень полезно: D –

-1

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


streambuf.commit(number_of_bytes_read); 

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

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

+4

operator >> (istream &, string &) копирует только до первого пробела – tstenner

+0

О, забыл об этом :) –

+0

@tstenner Существует флаг, чтобы отключить это поведение, а также поскольку другие флаги добавляют разные типы поведения. – Etherealone

23

Другая возможность с 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); 

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

+0

, откуда взялась длина? –

+0

Это количество байтов, которое вы взяли из потока. См. Http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/basic_streambuf/consume.html – tstenner

+0

Что вы имеете в виду с 'normal streambufs'? Ответ Шона ДеНигриса на основании документации недействителен? – ChrisPeterson

0

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

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

12

Для 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

+0

Этот ответ определенно лучше, если вы используете 'async_read_until', потому что этот вызов может возвращать более одной строки данных, и этот ответ правильно оставляет дополнительные данные в' streambuf'. –

36

Пришло действительно похоронен in the docs. ..

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); 
+3

Это хорошо работает! Вы можете использовать 'b.size()' вместо 'buf_size', если хотите, чтобы вся вещь была помещена в строку. – Malvineous

+1

Предполагается, что ответ tstenner выше, где он говорит, что он считается грязным и не будет работать с «нормальными streambufs», применим к этому ответу или этот способ считается безопасным? – ChrisPeterson

1

Можно также получить символы из 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); 
-1

Я проверил первый ответ и получил ошибку компилятора при компиляции с использованием «г ++ -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

haha ​​это выводит указатель на ответ. – thang

0

Более простой ответ был бы преобразовать его в 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

Это тот же ответ, что и Шон Де Нигрис ... который он опубликовал 4 года назад! –

Смежные вопросы