C++ 是否可以将 fstream 对象设置为在每次调用 << 时自动写入换行符?
C++ Can an fstream object be set to automatically write a newline on each call to <<?
我创建了一个 fstream 对象来将信息写入文件。
我将字符串写入新文件,如
fStreamObject << "New message.\n";
因为我希望每个 << 都在下一行打印一个字符串。
我希望能够设置一个属性并像
一样拨打电话
fstreamObject << "New message.";
这会将字符串写入下一行。
是否有 flags/settings 允许这样做的 fstream 对象?
我见过不同的文件模式(即 ofstream::in、ofstream::out 等),但找不到自动写入新行的文件模式。另外,我不想编写自己的解决方案。我希望能够使用内置功能。
不,标准 流中没有那种易于配置的功能。
您可能必须将流类型和 fiddle 子类化为 operator<<
才能使其按您想要的方式工作,或者使用某种描述的辅助函数来实现:
fstreamObject << nl("New message.");
(但这并不比只在其中放置 \n
更容易(无论如何对于字符串)。
不,C++ 流不允许这样做。
无法决定一个插入停止和下一个插入开始的位置。
例如,对于自定义类型,它们的流插入器通常被实现为对其他流插入器和成员函数的调用。
您可以做的唯一事情就是编写您自己的 class,它委托给您选择的流,然后执行此操作。
不过,那是严格有限的用途。
struct alwaysenter {
std::ostream& o;
template<class X> alwaysenter& operator<<(X&& x) {
o<<std::forward<X>(x);
return *this;
}
};
这取决于你所说的 "setting the stream" 是什么意思。如果我们认为这相当广泛,那么答案恰好是 "yes"!
方法如下:
- 创建一个流缓冲区,每次刷新时插入一个换行符,即调用
sync()
时。否则它只会转发字符。
- 更改文件流的流缓冲区以将此流缓冲区过滤用于文件流的流缓冲区。
- 设置标志
std::ios_base::unitbuf
,在每次[正确编写的]输出操作后导致刷新。
下面是执行此操作的示例代码:
#include <iostream>
class newlinebuf
: public std::streambuf {
std::ostream* stream;
std::streambuf* sbuf;
int overflow(int c) { return this->sbuf->sputc(c); }
int sync() {
return (this->sbuf->sputc('\n') == std::char_traits::eof()
|| this->sbuf->pubsync() == -1)? -1: 0;
}
public:
newlinebuf(std::ostream& stream)
: stream(&stream)
, sbuf(stream.rdbuf(this)) {
stream << std::unitbuf;
}
~newlinebuf() { this->stream->rdbuf(this->sbuf); }
};
int main() {
newlinebuf sbuf(std::cout);
std::cout << "hello" << "world";
}
虽然这种方法有效,但我建议反对使用它!问题是所有复合输出运算符,即那些使用多个输出运算符来完成工作的运算符,都会导致多个换行符。我不知道可以做些什么来防止这种行为。标准库中没有任何东西可以仅配置流来执行此操作:您需要以某种方式插入换行符。
我创建了一个 fstream 对象来将信息写入文件。 我将字符串写入新文件,如
fStreamObject << "New message.\n";
因为我希望每个 << 都在下一行打印一个字符串。
我希望能够设置一个属性并像
一样拨打电话fstreamObject << "New message.";
这会将字符串写入下一行。
是否有 flags/settings 允许这样做的 fstream 对象?
我见过不同的文件模式(即 ofstream::in、ofstream::out 等),但找不到自动写入新行的文件模式。另外,我不想编写自己的解决方案。我希望能够使用内置功能。
不,标准 流中没有那种易于配置的功能。
您可能必须将流类型和 fiddle 子类化为 operator<<
才能使其按您想要的方式工作,或者使用某种描述的辅助函数来实现:
fstreamObject << nl("New message.");
(但这并不比只在其中放置 \n
更容易(无论如何对于字符串)。
不,C++ 流不允许这样做。
无法决定一个插入停止和下一个插入开始的位置。
例如,对于自定义类型,它们的流插入器通常被实现为对其他流插入器和成员函数的调用。
您可以做的唯一事情就是编写您自己的 class,它委托给您选择的流,然后执行此操作。
不过,那是严格有限的用途。
struct alwaysenter {
std::ostream& o;
template<class X> alwaysenter& operator<<(X&& x) {
o<<std::forward<X>(x);
return *this;
}
};
这取决于你所说的 "setting the stream" 是什么意思。如果我们认为这相当广泛,那么答案恰好是 "yes"!
方法如下:
- 创建一个流缓冲区,每次刷新时插入一个换行符,即调用
sync()
时。否则它只会转发字符。 - 更改文件流的流缓冲区以将此流缓冲区过滤用于文件流的流缓冲区。
- 设置标志
std::ios_base::unitbuf
,在每次[正确编写的]输出操作后导致刷新。
下面是执行此操作的示例代码:
#include <iostream>
class newlinebuf
: public std::streambuf {
std::ostream* stream;
std::streambuf* sbuf;
int overflow(int c) { return this->sbuf->sputc(c); }
int sync() {
return (this->sbuf->sputc('\n') == std::char_traits::eof()
|| this->sbuf->pubsync() == -1)? -1: 0;
}
public:
newlinebuf(std::ostream& stream)
: stream(&stream)
, sbuf(stream.rdbuf(this)) {
stream << std::unitbuf;
}
~newlinebuf() { this->stream->rdbuf(this->sbuf); }
};
int main() {
newlinebuf sbuf(std::cout);
std::cout << "hello" << "world";
}
虽然这种方法有效,但我建议反对使用它!问题是所有复合输出运算符,即那些使用多个输出运算符来完成工作的运算符,都会导致多个换行符。我不知道可以做些什么来防止这种行为。标准库中没有任何东西可以仅配置流来执行此操作:您需要以某种方式插入换行符。