asio :: streambuf to std :: istream丢弃新行

时间:2016-07-04 22:51:28

标签: c++ c++11 boost-asio

我需要使用从asio :: socket(带有ASIO_STANDALONE)读取的数据作为istream

到目前为止,我有这段代码

asio::error_code ec;
auto bytes_transferred = asio::read_until(socket, buffer, '\n', ec);

if(!ec)
{
    buffer.commit(bytes_transferred);
    std::istream line(&buffer);
    // use line
    buffer.consume(bytes_transferred);
}

我面临的问题是'\n'出现在istream的末尾,因为它不会被read_until丢弃。

声明是

tcp::socket socket;
asio::streambuf buffer;

所以我需要忽略' \ n'构造流时的char。 我尝试了(正如我在这个问题efficient copy of data from boost::asio::streambuf to std::string中看到的)

if(!ec)
{
    // Ignore the last char ('\n')
    std::string line = std::string(asio::buffers_begin(buffer),
                                   asio::buffers_begin(buffer) + bytes_transferred - 1);
    std::stringstream ss(line);
    // use line
    buffer.consume(bytes_transferred);
}

但是这会产生以下编译错误

In instantiation of ‘struct asio::detail::buffers_iterator_types<asio::basic_streambuf<>, char>’:
lib/asio/asio/buffers_iterator.hpp:77:46:   required from ‘class asio::buffers_iterator<asio::basic_streambuf<>, char>’
file.h:58:78:   required from here
lib/asio/asio/buffers_iterator.hpp:60:5: error: no type named ‘value_type’ in ‘class asio::basic_streambuf<>’
     {
     ^
lib/asio/asio/buffers_iterator.hpp: In instantiation of ‘class asio::buffers_iterator<asio::basic_streambuf<>, char>’:
file.h:58:78:   required from here
lib/asio/asio/buffers_iterator.hpp:455:43: error: no type named ‘const_iterator’ in ‘class asio::basic_streambuf<>’
   typename BufferSequence::const_iterator begin_;

还有一些人总是抱怨缺少类型。 我对C ++很新,这个消息对我来说有点神秘,而且我不确定这是最好的方法,因为我将有3份相同的数据(在缓冲区中,在字符串和流中)

什么可能解决我的问题?

2 个答案:

答案 0 :(得分:2)

这里有很多方法,但如果不了解您打算如何使用istream,就很难提出好的建议。

关于此代码的一件事是,您绝对肯定地知道istream末尾会有换行符。没有可以采用的代码路径不会导致这种情况(除了I / O错误,您将提前捕获)。

因此,编写期望\n存在并忽略它的代码非常简单。

显然,如果可能,你想避免使用缓冲区副本。

但是,如果要将整个streambuf复制到字符串中,可以尝试这样做:

auto buf = buffer.data(); /* where buffer is your asio::streambuf */
auto s = std::string(boost::asio::buffer_cast<const char*>(buf), 
                     boost::asio::buffer_size(buf) - 1); /* remove the newline */

当然,如果你想要解析istream中的字符串,数字等,那么最后有一个换行的事实并不重要 - 它只是空格,默认情况下会被忽略。

这个迷你程序证明了这一点:

#include <boost/asio.hpp>
#include <sstream>
#include <iomanip>
#include <iostream>


int main()
{
    std::ostringstream oss;

    oss << 10 << std::quoted("Hello\" World") << '\n';
    auto payload = oss.str();

    boost::asio::streambuf sb;
    std::ostream otmp(&sb);
    otmp.write(payload.data(), payload.size());

    // streambuf now contains string with newline

    std::string s;
    int i;
    std::istream itmp(&sb);
    itmp >> i >> std::quoted(s);

    std::cout << i << std::endl;   // expect 10
    std::cout << s << std::endl;   // expect Hello" World
}

答案 1 :(得分:1)

缓冲区迭代器假设您没有使用streambuf。如果你可以接收一个完全有用的缓冲区(序列)。

但是,您可以使用

  1. streambuf迭代器:

    std::string line;
    // Ignore the last char ('\n')
    std::copy_n(std::istreambuf_iterator<char>(&buffer), bytes_transferred - 1, back_inserter(line));
    

    <强> Live On Coliru

  2. iostream空白感知功能(例如std::getlinestd::skipws,默认情况下启用)。