Подтвердить что ты не робот

Использует ли запись в С++ ofstream буфер?

Ниже приведены две программы, которые записывают 50 000 000 байтов в файл.

В первой программе, написанной на C, используется буфер, который после заполнения до произвольного значения записывается на диск, а затем повторяет этот процесс до тех пор, пока не будут записаны все 50 000 000 байтов. Я заметил, что по мере увеличения размера буфера программе потребовалось меньше времени для запуска. Например, в BUFFER_SIZE = 1 программа заняла ~ 88.0463 секунды, тогда как в BUFFER_SIZE = 1024 программа заняла ~ 1.7773 секунды. Лучшее время, которое я записал, было когда BUFFER_SIZE = 131072. Поскольку BUFFER_SIZE увеличилось выше этого, я заметил, что он начал набирать немного больше времени.

Вторая программа, написанная на С++, использует forstream для записи по одному байту за раз. К моему удивлению, программа заняла всего 1,87 секунды. Я ожидал, что это займет минуту или около того, как программа C с BUFFER_SIZE = 1. Очевидно, что С++ ofstream обрабатывает запись файлов по-другому, чем я думал. По моим данным, он довольно похож на файл C с BUFFER_SIZE = 512. Использует ли он какой-то закулисный буфер?

Вот программа 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);
}

Вот программа С++:

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

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

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

    return 0;
}

Спасибо за ваше время.

4b9b3361

Ответ 1

Да, ostreams используют буфер потока, некоторый подкласс экземпляра шаблона basic_streambuf. Интерфейс basic_streambuf сконструирован таким образом, что реализация может выполнять буферизацию, если в этом есть преимущество.

Однако это проблема качества реализации. Реализации не требуются для этого, но любая компетентная реализация будет.

Вы можете прочитать все об этом в главе 27 стандарта ISO, хотя, возможно, более читаемым источником является стандартная библиотека С++: учебник и справочник (google поиск).

Ответ 2

Да, все потоковые операции буферизованы, хотя по умолчанию стандартный вывод, вывод и вывод ошибки не так, что взаимодействие с 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;
}

Теперь вы можете повторить эксперименты, которые вы сделали на C, чтобы найти сладкое пятно:)

Ответ 3

Per this, ofstream имеет внутренний указатель filebuf, может быть прочитан через функцию rdbuf, которая указывает на streambuf, который является следующим:

streambuf объекты обычно связаны с одним конкретным символом последовательность, из которой они считывают и записывают данные через внутренний буфер памяти. Буфер представляет собой массив в памяти, который, как ожидается, синхронизироваться по мере необходимости с физическим содержимым ассоциированная последовательность символов.

Я выделил важные биты, кажется, что он использует буфер, но я не знаю или не узнал, что это за буфер.