2015-05-29 4 views
5

Я знаю, что это будет довольно глупый вопрос, но после прочтения так много документа о всей «буферной» системе, я не могу понять, почему люди будут очищать поток, но не буфер.Почему мы очищаем поток, но не буфер?

Я видел, что люди пишут вещи, как это:

FILE* file=fopen("mytext.txt","wr"); 
char buffer[10]=""; 
setbuf(file,buffer); 

//do some stuff.... 

fflush(file); 
.... 
fclose(file); 

Так интересно, так как мы на самом деле хранить вещи в буфере, почему мы промывать поток он связан с, а не очищать буфер непосредственно, , который на самом деле что-то хранит и должен быть покраснел. (Ну, некоторые люди говорят мне, что если все будет похоже на то, что я сказал, это будет то же самое, что и я сам себя беспокою ......)

Например, мы не можем писать такие вещи, как fflush(buffer). Почему?

+5

В вашем доме вы говорите «очистить фекальную материю» или «смыть туалет»? :-) Промывка - это свойство туалета/потока, а не цензуры/данных. – paxdiablo

+0

не относится: '' wr '' ??, shoud be 'char buffer [BUFSIZ];' – BLUEPIXY

+0

@milleniumbug '' wr '' и '' rw "' оба являются недопустимыми файловыми режимами. – BLUEPIXY

ответ

6

Промывка копирует данные из внутреннего буфера потока в основной файл.

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

Это зависит от реализации ввода-вывода, для C++ <iostream> см. Ответ Джерри Коффина - буферы в <iostream> более умны.

С C-style <cstdio>, если вы хотите сбросить только один аргумент, либо FILE*, либо массив символов должен знать о файле, который он должен скопировать.

Ваш буфер - это глупый массив, он просто хранит данные для чтения/записи. Поскольку там нет дополнительной информации, функция, которая получает указатель на буфер, не может знать место назначения, где его писать, - поэтому мнимый вызов fflush будет выглядеть как fflush(buffer, file);, который нигде не доставит вас. С другой стороны, FILE* хранит указатель на ваш буфер (вы устанавливаете указатель с вызовом функции).

+0

Собственно, milleniumbug прав. Вопрос задавал вопрос о функциях stdio.h, а не в потоках C++, вопреки тому, что подразумевалось под заголовком вопроса. В примере кода ясно, что буфер является указателем char *, и вопрос относится к функциям setbuf и fflush. Этот указатель действительно не знает об этом файле. –

+0

@JerryCoffin Отправил ответ немного (он был слишком неряшлив со словами «поток», «буфер» и «файл»). – milleniumbug

+0

@DavidRoundy: Ах, хорошая точка. Я уделял слишком много внимания тегу и недостаточно для примера кода. –

2

Следующие действия относятся только к iostreams и их буферным объектам. Информацию о буферах, связанных с вводом-выводом C-стиля, см. В ответе @ milleniumbug.

В основном потому, что вы (по крайней мере, обычно) хотите, чтобы битбад потока был установлен, если попытка сбросить базовый буфер не удалась.

Существует также немного сложный маленький танец, который использует потоки при взаимодействии с базовым потоком, где поток создает объект часовой стрелки, а затем выполняет действие, затем объект-сторож уничтожается. Часовой призван сделать префикс и операции суффикса безопасными.

Таким образом, общая последовательность что-то вроде этого:

create sentry 
if that succeeds (sentry converts to true) call rdbuf()->pubsync() 
    if that fails (returns -1) setstate(badbit); 

буфер потока (например, basic_filebuf) непосредственно присоединен к основному объекту файловой системы - на самом деле, все взаимодействие между объектом iostream и основной файл-объект выполнен через файловый буфер. Как показано выше, когда объекту потока необходимо сбросить буфер, все, что ему нужно сделать, указывает, что буфер сбросится сам, вызвав функцию-член pubsync().

[Для справки: [ostream.неформатированные]/7:

basic_ostream & flush();

Эффекты: Работает как неформатированная выходная функция (как описано в пункте 27.7.3.6.1, пункт 1). Если rdbuf() не является нулевым указателем, он создает объект-часовую. Если этот объект возвращает true при преобразовании в значение типа bool, функция вызывает rdbuf() -> pubsync(). Если эта функция возвращает -1 вызовов setstate (badbit) (которые могут вызывать ios_base :: failure (27.5.5.4)). В противном случае, если сторожевой объект возвращает false, ничего не делает.

Возврат: * этот.

... и [ofstream.cons]/2:

явное basic_ofstream (Const символ * s, ios_base :: Режим OpenMode = ios_base :: из);

Эффекты: Создает объект класса basic_ofstream, инициализирует базовый класс с basic_ostream (& SB) и инициализирующий ОПБ с basic_filebuf()) (27.7.3.2, 27.9.1.2), затем вызывает rdbuf() -> open (s, mode | ios_base :: out). Если эта функция возвращает нулевой указатель, вызывает setstate (failbit).

0

Я не могу понять, почему люди промывать поток, но не буфер.

Поскольку буфер не знает, где его следует покрасить. Поток делает.

FILE* file=fopen("mytext.txt","wr"); 
setbuf(file,buffer); 

По умолчанию FILE структура содержит указатель на свой собственный внутренний буфер. setbuf() заменяет этот буфер тем, который предоставляет вызывающий. Но в любом случае fwrite(), fput...() и другие подобные функции записывают данные в текущий буфер потока, а fflush() сбрасывает содержимое этого буфера в основной файл.

КСТАТИ setbuf() требует буфера вызывающего абонента, при условии, что по размеру, по меньшей мере BUFSIZ:

char buffer[BUFSIZ]=""; 

Так интересно, так как мы на самом деле хранить вещи в буфере, почему мы промывать поток его ассоциируется, а не просто сбрасывает буфер непосредственно, который на самом деле что-то хранит и должен быть очищен.

Потому что буфер - это просто хранилище данных. Он ничего не знает о том, как используются данные. Поток знает, к чему его буфер используется (кэш-записи), и где его нужно очистить (связанный файл). Таким образом, вы должны очистить поток, чтобы он мог использовать эту информацию.

Например, мы не можем писать такие вещи, как fflush (buffer). Зачем?

И где вы ожидаете, что буфер будет содержать содержимое своего контента? Он не имеет такой информации.

Смежные вопросы