std :: ofstream-没有比1023(即时冲洗)更长的缓冲字符串
std::ofstream - no buffering string longer than 1023 (instant flush)
当我用 pubsetbuf(...)
更改ofstream
缓冲区的大小时,一切都很好,除非我将单字符串放到ofstream
更长的1023
(在下面的代码中(。这是正确的行为还是我做错了什么?
int main(){
std::vector<char> rawBuf;
std::ofstream stream;
rawBuf.resize(20000);
stream.rdbuf()->pubsetbuf(&rawBuf[0], 20000);
stream.open("file.txt", std::ios_base::app);
std::string data(1499, 'b');
for(int i = 0; i < 10; i++)
{
stream << data.substr(0, 1024) << "n"; //1023-length string works great
sleep(1);
}
stream.flush();
stream.close();
return 0;
}
有1024长的字符串strace ./program
显示出类似的内容:
writev(3, [{iov_base=NULL, iov_len=0}, {iov_base="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"..., iov_len=1024}], 2) = 1024
nanosleep({tv_sec=1, tv_nsec=0}, 0x7ffcf3889ac0) = 0
writev(3, [{iov_base="n", iov_len=1}, {iov_base="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"..., iov_len=1024}], 2) = 1025
nanosleep({tv_sec=1, tv_nsec=0}, 0x7ffcf3889ac0) = 0
... and so on 10x
有1023个长度的字符串时,一切似乎都可以:
nanosleep({tv_sec=1, tv_nsec=0}, 0x7fff8e13a980) = 0
nanosleep({tv_sec=1, tv_nsec=0}, 0x7fff8e13a980) = 0
... 10x
,然后:
write(3, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"..., 10240) = 10240
为什么这里有单个写作,而更早的写作?
编辑:
gcc version 7.3.0 (Ubuntu 7.3.0-16ubuntu3)
per [filebuf.virtuals]/12:
basic_streambuf* setbuf(char_type* s, streamsize n) override;
效果:如果在该流上发生任何I/O之前在流上调用
setbuf(0, 0)
,则该流未掩盖。否则 结果是实施定义的。"无封闭"表示pbase()
pptr()
始终将null和输出返回到文件应显示 尽快。
"实现定义"包括"工作正常"answers"只有单个写作"和其他内容。实际上,这是libstdc 7.3.0说的:
首先,您确定自己了解缓冲吗?特别是 实际上,C 可能与它没有任何关系吗?
缓冲规则可能有些奇怪,但它们不是任何 与C的不同。(也许这就是为什么它们有点奇怪。( 许多人认为为输出流编写新线 自动冲洗输出缓冲区。只有当 实际上,输出流是终端,而不是文件或其他一些 设备 - 这甚至可能是不正确的,因为C 什么也没说 文件或终端。所有这些都是依赖于系统的。(这 "仅发生在终端上的newline-buffer燃烧"主要是 不过,在Unix系统上是正确的。(
有些人还认为仅发送端口仅向下发送输出流 写一个新线。这是不正确的;编写新线后, 缓冲区也被冲洗。也许这是您想要的效果 写在屏幕上 - 尽快将文本删除,等等 - 但是,在将其执行到文件时,缓冲大部分是浪费的:
output << "a line of text" << endl; output << some_data_variable << endl; output << "another line of text" << endl;
在这种情况下,要做的适当的事情只是将数据写出来,然后让 库和系统担心缓冲。如果您需要一个 newline,只需写一个newline:
output << "a line of textn" << some_data_variable << 'n' << "another line of textn";
我也将输出语句加入了一个语句。你 可以通过将单个新线移至"开始"来使代码更漂亮 例如,最后一行的引用文本。
如果您确实需要冲洗上方的缓冲区,则可以发送
endl
您还需要一个新线,或者自己冲洗缓冲区:output << ...... << flush; // can use std::flush manipulator output.flush(); // or call a member fn
另一方面,有时应该写入文件 就像写入标准错误一样;不应该进行缓冲,因为 数据需要快速出现(一个典型示例是日志文件 与安全有关的信息(。这样做的方法只是关闭 所有I/O操作之前都已经完成了缓冲(注意 该开口计为I/O操作(:
std::ofstream os; std::ifstream is; int i; os.rdbuf()->pubsetbuf(0,0); is.rdbuf()->pubsetbuf(0,0); os.open("/foo/bar/baz"); is.open("/qux/quux/quuux"); ... os << "this data is written immediatelyn"; is >> i; // and this will probably cause a disk read
由于缓冲的所有方面均由
streambuf
衍生 成员,有必要使用rdbuf()
获得该成员。然后 可以调用setbuf
的公共版本。论点是相同的 作为标准C I/O库功能(缓冲区区域( 其次是大小(。其中很大程度上取决于实现。例如,
streambuf
没有为其自己的setbuf()
指定任何动作 功能;从streambuf
派生的类定义行为 对于该类别的"有意义":(0,0)
的论点关闭filebuf
的缓冲,但对其兄弟姐妹一无所有stringbuf
和strstreambuf
,并指定除(0,0)
具有不同的效果。从用户定义的类派生的类streambuf
可以做任何他们想做的事情。(对于filebuf
和参数 对于(p,s)
,除了零以外,Libstdc 可以做您期望的事情:p
的第一个s
字节用作缓冲区,您必须分配 和DealLocate。(最后提醒:通常涉及的缓冲区不仅仅是 那些在语言/图书馆级别。内核缓冲区,磁盘缓冲区和 类似也会产生效果。检查和更改这些是 依赖系统。