使用std::ostream在每行之前插入文本
inserting text before each line using std::ostream
我想知道是否有可能从std::ostream继承,并以这样一种方式重写flush(),即将一些信息(例如,行号)添加到每行的开头。然后我想通过rdbuf()将它附加到std::ofstream(或cout),这样我就得到了这样的东西:
ofstream fout("file.txt");
myostream os;
os.rdbuf(fout.rdbuf());
os << "this is the first line.n";
os << "this is the second line.n";
会将其放入file.txt
1 this is the first line.
2 this is the second line.
flush()
不是在此上下文中要覆盖的函数,尽管您的思路是正确的。应该在底层的std::streambuf
接口上重新定义overflow()
。例如:
class linebuf : public std::streambuf
{
public:
linebuf() : m_sbuf() { m_sbuf.open("file.txt", std::ios_base::out); }
int_type overflow(int_type c) override
{
char_type ch = traits_type::to_char_type(c);
if (c != traits_type::eof() && new_line)
{
std::ostream os(&m_sbuf);
os << line_number++ << " ";
}
new_line = (ch == 'n');
return m_sbuf.sputc(ch);
}
int sync() override { return m_sbuf.pubsync() ? 0 : -1; }
private:
std::filebuf m_sbuf;
bool new_line = true;
int line_number = 1;
};
现在你可以这样做:
linebuf buf;
std::ostream os(&buf);
os << "this is the first line.n"; // "1 this is the first line."
os << "this is the second line.n"; // "2 this is the second line."
<<p> 生活例子/kbd> James Kanze关于过滤流bufs的经典文章有一个非常相似的例子,在每行的开头放置一个时间戳。你可以修改代码
或者,您也可以使用从那篇文章的思想中衍生出来的Boost工具。
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/array.hpp>
#include <cstring>
#include <limits>
// line_num_filter is a model of the Boost concept OutputFilter which
// inserts a sequential line number at the beginning of every line.
class line_num_filter
: public boost::iostreams::output_filter
{
public:
line_num_filter();
template<typename Sink>
bool put(Sink& snk, char c);
template<typename Device>
void close(Device&);
private:
bool m_start_of_line;
unsigned int m_line_num;
boost::array<char, std::numeric_limits<unsigned int>::digits10 + 4> m_buf;
const char* m_buf_pos;
const char* m_buf_end;
};
line_num_filter::line_num_filter() :
m_start_of_line(true),
m_line_num(1),
m_buf_pos(m_buf.data()),
m_buf_end(m_buf_pos)
{}
// put() must return true if c was written to dest, or false if not.
// After returning false, put() with the same c might be tried again later.
template<typename Sink>
bool line_num_filter::put(Sink& dest, char c)
{
// If at the start of a line, print the line number into a buffer.
if (m_start_of_line) {
m_buf_pos = m_buf.data();
m_buf_end = m_buf_pos +
std::snprintf(m_buf.data(), m_buf.size(), "%u ", m_line_num);
m_start_of_line = false;
}
// If there are buffer characters to be written, write them.
// This can be interrupted and resumed if the sink is not accepting
// input, which is why the buffer and pointers need to be members.
while (m_buf_pos != m_buf_end) {
if (!boost::iostreams::put(dest, *m_buf_pos))
return false;
++m_buf_pos;
}
// Copy the actual character of data.
if (!boost::iostreams::put(dest, c))
return false;
// If the character copied was a newline, get ready for the next line.
if (c == 'n') {
++m_line_num;
m_start_of_line = true;
}
return true;
}
// Reset the filter object.
template<typename Device>
void line_num_filter::close(Device&)
{
m_start_of_line = true;
m_line_num = 1;
m_buf_pos = m_buf_end = m_buf.data();
}
int main() {
using namespace boost::iostreams;
filtering_ostream myout;
myout.push(line_num_filter());
myout.push(std::cout);
myout << "this is the first line.n";
myout << "this is the second line.n";
}
相关文章:
- 找不到最新插入到 std::map 中的键
- 将带有模板的自定义类插入到 std::map 中
- 为什么第 32769 个插入在 std::unordered_set 中失败
- 如何将带有前导零的整数插入到 std::string 中
- 为什么插槽函数即使成功调用也无法插入文本
- 将项目插入到std :: map时错误
- 将列表初始化的对插入到 std::map 中
- 将没有默认 ctor 的对象插入到 std::map
- fputc在插入文本之前将第一行留空
- 无法将 std::set 中的元素迭代器插入到 std::list
- 在Embarcadero Tools API中的光标位置插入文本
- 修改最后插入到std :: map
- C++感知复制插入到std::映射中
- 如何将const std::shared_ptr插入到std::映射中
- C++直接插入到std::map中,而不使用赋值运算符
- 将 OpenCv 垫插入 C++ std::vector
- 拆分 std::string 并插入到 std::set 中
- 为什么编译器说我不能将项插入到 std::set 中<Item>?
- 插入到 std::map 中,同时迭代它
- 使用std::ostream在每行之前插入文本