asio::streambuf 到 std::istream 丢弃新行
asio::streambuf to std::istream discarding new line
我需要使用从 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'字符。
我试过(正如我在这个问题 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 个副本(在缓冲区、字符串和流)
我的问题可能有什么解决方案?
缓冲区迭代器假定您没有使用 streambuf。如果您可以接收到一个完全有效的缓冲区(序列)。
但是,您也许可以只使用
streambuf 迭代器:
std::string line;
// Ignore the last char ('\n')
std::copy_n(std::istreambuf_iterator<char>(&buffer), bytes_transferred - 1, back_inserter(line));
iostream 空白感知功能(如 std::getline
和 std::skipws
,默认情况下 启用 )。
这里有很多方法,但是如果不了解您打算如何使用 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
}
我需要使用从 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'字符。 我试过(正如我在这个问题 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 个副本(在缓冲区、字符串和流)
我的问题可能有什么解决方案?
缓冲区迭代器假定您没有使用 streambuf。如果您可以接收到一个完全有效的缓冲区(序列)。
但是,您也许可以只使用
streambuf 迭代器:
std::string line; // Ignore the last char ('\n') std::copy_n(std::istreambuf_iterator<char>(&buffer), bytes_transferred - 1, back_inserter(line));
iostream 空白感知功能(如
std::getline
和std::skipws
,默认情况下 启用 )。
这里有很多方法,但是如果不了解您打算如何使用 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
}