将streambuf的内容复制到字符串

时间:2009-05-18 13:07:12

标签: c++ string boost boost-asio streambuf

显然boost::asio::async_read不喜欢字符串,因为boost::asio::buffer的唯一重载允许我创建const_buffer,所以我一直在阅读所有内容到streambuf。
现在我想将streambuf的内容复制到一个字符串中,但它显然只支持写入char *(sgetn()),使用streambuf创建一个istream并使用getline()

有没有其他方法可以使用streambufs内容创建一个字符串而无需过多复制?

11 个答案:

答案 0 :(得分:45)

我不知道它是否算作“过度复制”,但您可以使用字符串流:

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

就像,要读取从stdin到字符串的所有内容,请执行

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*,因此请根据需要使用其地址。还要注意最后一个示例中第一个参数周围的附加括号,这样它就不会将其解释为返回字符串并获取迭代器和另一个函数指针的函数声明(“最烦恼的解析”)。

答案 1 :(得分:37)

真的埋没in the docs ......

给定boost::asio::streambuf bsize_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);

答案 2 :(得分:24)

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不起作用,可能会被认为是脏的,但它似乎是最快的方式。

答案 3 :(得分:13)

对于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

答案 4 :(得分: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);

答案 5 :(得分:0)

你只能从std :: string创建const_buffer的原因是因为std :: string显然不支持在其契约中直接基于指针的写入。你可以做一些邪恶的事情,比如将你的字符串调整到一定的大小,然后从c_str()中const_cast the constness并将其视为一个原始的char *缓冲区,但这非常顽皮,有一天会让你陷入困境。

我使用std :: vector作为我的缓冲区,因为只要向量没有调整大小(或者你小心处理大小调整),你可以直接指针写入。如果我需要将某些数据作为std :: string,我必须将其复制出去,但是我处理读取缓冲区的方式,无论如何都需要复制任何需要超出读取回调的内容。

答案 6 :(得分:0)

更简单的答案是将其转换为PHCachingImageManager *imageManager = [PHCachingImageManager new]; CGSize canvasSize = CGSizeMake(100*self.uploadAssets.count, 100); UIGraphicsBeginImageContext(canvasSize); for (int i = 0; i < self.uploadAssets.count; i++){ if ([self.uploadAssets[i] isKindOfClass:[PHAsset class]]) { PHAsset *asset = self.uploadAssets[i]; [imageManager requestImageForAsset:asset targetSize:CGSizeMake(350,350) contentMode:PHImageContentModeAspectFill options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { if (result) { [result drawInRect:CGRectMake(i*100, 0, 100, 100)]; } }]; }else if ([self.uploadAssets[i] isKindOfClass:[Item class]]) { Item *item = self.uploadAssets[i]; NSURL *url = [NSURL URLWithString: item.images[0]]; NSData *imageData = [[NSData alloc] initWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:imageData]; [image drawInRect:CGRectMake(i*100, 0, 100, 100)]; } } UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); self.uploadImage = finalImage; 并对其进行操作

std::string

为任务提供非常简洁的代码。

答案 7 :(得分:0)

我通常不喜欢这样的回答:“您不想要X,您想要Y,这是Y的操作方法”,但是在这种情况下,我很确定自己知道tstenner想要什么。

在Boost 1.66中,添加了dynamic string buffer类型,因此var requiredSigners = Arrays.asList(oracle.owningKey, urIdentity.owningKey, lenderAccountNewKey) val output = IOUState(exchangeRate * value, lenderAccountNewKey, borrowerAccountNewKey) val transactionBuilder = TransactionBuilder(notary) var participantsList = ArrayList<AbstractParty>(output.participants) participantsList.add(oracle) transactionBuilder.addOutputState(output, IOUContract.ID) .addCommand(IOUContract.Commands.Create(), participantsList.map { it.owningKey }) transactionBuilder.verify(serviceHub) var localSignedTx = serviceHub.signInitialTransaction(transactionBuilder) var filteredTx = localSignedTx.buildFilteredTransaction(Predicate { when (it) { is Command<*> -> oracle.owningKey in it.signers else -> false } } val oracleSignature = subFlow(SignFlow(oracle, filteredTransaction)) val stx = locallySignedTransaction.withAdditionalSignature(oracleSignature) 可以直接调整大小并写入字符串缓冲区。

答案 8 :(得分:0)

我没有看到将 n 个字符准确读入 std::stringstream 的现有答案,因此可以这样做:

std::stringstream ss;
boost::asio::streambuf sb;
const auto len = 10;

std::copy_n(boost::asio::buffers_begin(sb.data()), len,
            std::ostream_iterator<decltype(ss)::char_type>(ss));

Compiler explorer

答案 9 :(得分:-2)

我认为它更像是:


streambuf.commit( number_of_bytes_read );

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

我没有查看basic_streambuf代码,但我相信这应该只是字符串中的一个副本。

答案 10 :(得分:-2)

我测试了第一个答案,并在使用&#34; g ++ -std = c ++ 11&#34;进行编译时遇到了编译错误。 对我有用的是:

        #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(); 

这编译并运行。