C++ ofstream文件写入是否使用缓冲区?

26 c++ file-io file

下面是两个将50,000,000字节写入文件的程序.

第一个用C语言编写的程序利用一个缓冲区,一旦填充到任意值,写入磁盘,然后重复该过程直到写入所有50,000,000个字节.我注意到,当我增加缓冲区的大小时,程序运行时间更短.例如,在BUFFER_SIZE = 1时,程序花了大约88.0463秒,而在BUFFER_SIZE = 1024时,程序只需要大约1.7773秒.我记录的最佳时间是BUFFER_SIZE = 131072.当BUFFER_SIZE增加高于此值时,我注意到它开始实际需要更长时间.

第二个用C++编写的程序利用ofstream一次写入一个字节.令我惊讶的是,该程序只用了1.87秒就可以运行了.我预计它需要一分钟左右,就像使用BUFFER_SIZE = 1的C程序一样.显然,C++ ofstream处理文件写入的方式与我想象的不同.根据我的数据,它的表现与BUFFER_SIZE = 512的C文件非常相似.它是否使用某种幕后缓冲区?

这是C程序:

const int NVALUES = 50000000; //#values written to the file
const char FILENAME[] = "/tmp/myfile";
const int BUFFER_SIZE = 8192; //# bytes to fill in buffer before writing

main()
{
    int fd;  //File descriptor associated with output file
    int i;
    char writeval = '\0';
    char buffer[BUFFER_SIZE];

    //Open file for writing and associate it with the file descriptor
    //Create file if it does not exist; if it does exist truncate its size to 0
    fd = open(FILENAME, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);

    for(i=0;i<NVALUES;i++)
    {
        //Package bytes into BUFFER_SIZE chunks 
                //and write a chunk once it is filled
        buffer[i%BUFFER_SIZE] = writeval;
        if((i%BUFFER_SIZE == BUFFER_SIZE-1 || i == NVALUES-1))
            write(fd, buffer, i%BUFFER_SIZE+1);

    }

    fsync(fd);

    close(fd);
}
Run Code Online (Sandbox Code Playgroud)

这是C++程序:

int main()
{
    ofstream ofs("/tmp/iofile2");
    int i;

    for(i=0; i<50000000; i++)
        ofs << '\0';

    ofs.flush();
    ofs.close();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

感谢您的时间.

Mat*_* M. 12

是的,所有流操作都是缓冲的,但默认情况下,标准输入,输出和错误输出不是这样,与C IO的交互就不那么令人惊讶了.

如前所述,有一个streambuf在幕后使用的基类.它提供了自己的缓冲区,其大小是一个实现细节.

您可以(通过实验)检查此缓冲区的使用量streambuf::in_avail,假设输入文件流和输出文件流设置为具有相同的缓冲区大小...

您可以在此处执行另外两项可能感兴趣的操作:

  • 您可以更改streambuf流使用的对象,以切换到自定义版本
  • 您可以更改streambuf对象使用的缓冲区

两者都应该在创建流之后或之后完成flush,以免某些数据丢失...

要说明缓冲区更改,请查看streambuf::putsetbuf:

#include <fstream>
#include <vector>

int main () {
  std::vector<char> vec(512);

  std::fstream fs;
  fs.rdbuf()->pubsetbuf(&vec.front(), vec.size());

  // operations with file stream here.
  fs << "Hello, World!\n";

  // the stream is automatically closed when the scope ends, so fs.close() is optional
  // the stream is automatically flushed when it is closed, so fs.flush() is optional

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在你可以重复你在C中做的实验来找到最佳位置:)


bam*_*s53 11

是的,ostreams使用流缓冲区,模板basic_streambuf的实例化的一些子类.basic_streambuf的接口被设计为如果有优势的话,实现可以进行缓冲.

然而,这是一个实施质量问题.实现不需要执行此操作,但任何有能力的实现都将.

您可以在ISO标准的第27章中阅读所有相关内容,但可能更可读的来源是C++标准库:教程和参考(谷歌搜索).