为何std::istream读操作未调用自定义filebuf的xsgetn()方法?
问题
我希望在通过std::istream读取关联文件、以及通过std::ostream写入关联文件时收到通知。为此我派生了自定义std::filebuf,并重写xsgetn()和xsputn()函数,让它们先向控制台输出信息再调用父类实现。测试代码中,写操作成功触发了自定义的xsputn(),但读操作(使用getline)虽执行成功,却从未调用自定义的xsgetn()。我还尝试重载std::basic_filebuf::uflow()和std::basic_filebuf::underflow(),这两个函数在读取时能成功触发,想了解xsgetn()未被调用的原因。
测试代码如下:
#include <iostream> #include <fstream> #include <cstdio> class MyFileBuff : public std::filebuf { public: std::streamsize xsgetn(char_type* s, std::streamsize count) override { std::cout << "using my xsgetn()" << std::endl; return std::filebuf::xsgetn(s, count); } std::streamsize xsputn(const char_type* s, std::streamsize count) override { std::cout << "using my xsputn()" << std::endl; return std::filebuf::xsputn(s, count); } using std::filebuf::basic_filebuf; }; int main() { //open file FILE* filePtr{ nullptr }; fopen_s(&filePtr, "text.txt", "w+"); //associate file with instance of custom std:filebuff MyFileBuff fileBuff(filePtr); //initalize i/o streams with file buffer std::istream myIStream(&fileBuff); std::ostream myOStream(&fileBuff); //output to file myOStream << "hello world" << std::endl; const short buffSize{ 1024 }; char buff[buffSize]; myIStream.seekg(0); //read from file myIStream.getline(buff, buffSize); //output what was read to console std::cout << buff << std::endl; return 0; }
程序输出:
using my xsputn() hello world
原因分析
std::istream::getline的默认实现是逐个字符读取,直到遇到换行符或达到指定长度限制。这个过程中,它会反复调用std::basic_streambuf::sbumpc(),而sbumpc()最终会触发underflow()或uflow()来填充缓冲区并获取单个字符——这就是你重载这两个函数能收到通知的原因。
而xsgetn()是用于批量读取多个字符的底层接口,只有当调用std::istream::read()这类明确要求批量读取的成员函数时,才会直接调用xsgetn()。getline并没有使用批量读取逻辑,自然不会触发你重载的xsgetn()。
如果想要让读操作触发xsgetn(),可以把getline替换为read:
myIStream.read(buff, buffSize);
这样就能看到自定义的xsgetn()被调用的输出了。
内容的提问来源于stack exchange,提问作者wigi426
相关产品推荐
相关产品推荐

