Copier le contenu d'un streambuf à une chaîne
-
22-08-2019 - |
Question
Apparemment boost::asio::async_read
n'aime pas les chaînes, comme la seule surcharge de boost::asio::buffer
me permet de créer const_buffer
s, donc je suis coincé avec la lecture tout en streambuf.
Maintenant, je veux copier le contenu du streambuf dans une chaîne, mais il supporte apparemment seulement écrit char * (sgetn()
), la création d'un istream avec le streambuf et en utilisant getline()
.
Y at-il une autre façon de créer une chaîne avec le contenu de la copie sans streambufs excessive?
La solution
Je ne sais pas si ce compte comme " copie excessive ", mais vous pouvez utiliser un stringstream:
std::ostringstream ss;
ss << someStreamBuf;
std::string s = ss.str();
Comme, de lire tout de stdin dans une chaîne, faire
std::ostringstream ss;
ss << std::cin.rdbuf();
std::string s = ss.str();
Vous pouvez également utiliser un istreambuf_iterator
. Vous devrez mesurer si ce ou la manière ci-dessus est plus rapide -. Je ne sais pas
std::string s((istreambuf_iterator<char>(someStreamBuf)),
istreambuf_iterator<char>());
Notez que someStreamBuf
ci-dessus est censé représenter un streambuf*
, afin de prendre son adresse, le cas échéant. Notez également les parenthèses supplémentaires dans le premier argument dans le dernier exemple, de sorte qu'il ne l'interprète pas comme une déclaration de fonction renvoyant une chaîne et prendre un itérateur et un autre pointeur de fonction ( « parse le plus contrariant »).
Autres conseils
Il est vraiment enterré dans la documentation ...
Compte tenu boost::asio::streambuf b
, avec 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);
Une autre possibilité avec boost::asio::streambuf
est d'utiliser boost::asio::buffer_cast<const char*>()
conjointement avec boost::asio::streambuf::data()
et boost::asio::streambuf::consume()
comme ceci:
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);
Cela ne fonctionne pas avec streambufs normal et peut être considéré comme sale, mais il semble être le moyen le plus rapide de le faire.
Pour boost::asio::streambuf
vous pouvez trouver une solution comme ceci:
boost::asio::streambuf buf;
/*put data into buf*/
std::istream is(&buf);
std::string line;
std::getline(is, line);
Imprimer la chaîne:
std::cout << line << std::endl;
Vous trouverez ici: http: // www. boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/async_read_until/overload3.html
On peut aussi obtenir les caractères de asio::streambuf
en utilisant 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);
La raison pour laquelle vous ne pouvez créer const_buffer de std :: string est parce que std :: string ne supporte pas explicitement l'écriture à base de pointeur direct dans son contrat. Vous pouvez faire quelque chose comme mal redimensionner votre chaîne à une certaine taille, puis const_cast la constness de c_str () et de la traiter comme un tampon charbon brut *, mais c'est très méchant et vous obtiendrez un jour en difficulté.
J'utilise std :: vecteur pour mes tampons parce que tant que le vecteur ne redimensionne pas (ou si vous êtes prudent de traiter avec le redimensionnement), vous pouvez faire l'écriture pointeur direct très bien. Si j'ai besoin des données en tant que std :: string, je dois le copier, mais la façon dont je traite mes tampons de lecture, tout ce qui doit durer au-delà du rappel de lecture doit être copié sur quel que soit.
A serait de réponse plus simple convertir en std::string
et manipuler un peu comme ça que
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;
}
Donner un code très concis pour la tâche.
Je pense qu'il est plus comme:
streambuf.commit( number_of_bytes_read );
istream istr( &streambuf );
string s;
istr >> s;
Je ne l'ai pas regardé dans le code basic_streambuf
, mais je crois que cela devrait être juste une copie dans la chaîne.
Je l'ai testé la première réponse et a obtenu une erreur de compilation lors de la compilation en utilisant « g ++ std = c ++ 11 » Ce qui a fonctionné pour moi était:
#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();
compilé et a couru.