Будет ли функция fseek сбрасывать данные в буфер в C++?

Мы знаем, что вызов таких функций, как fprintf или fwrite, не приведет к немедленной записи данных на диск, вместо этого данные будут помещены в буфер до тех пор, пока не будет достигнуто пороговое значение. У меня вопрос: если я вызову функцию fseek, будут ли эти буферизованные данные записаны на диск перед поиском новой позиции? Или данные все еще в буфере и записываются в новую позицию?

Ченг


person cheng    schedule 21.09.2011    source источник


Ответы (5)


Я не знаю, гарантированно ли буфер будет сброшен, это может быть не так, если вы ищете позицию достаточно близко. Однако буферизованные данные не могут быть записаны в новую позицию. Буферизация — это всего лишь оптимизация, поэтому она должна быть прозрачной.

person K-ballo    schedule 21.09.2011
comment
Итак, вы имеете в виду, что с такими вызовами все в порядке: (1) fwrite... (2) fseek... (3) fwrite... и все данные будут в правильном положении? - person cheng; 21.09.2011
comment
Да, вы можете быть уверены, что fseek будет работать так же, как если бы вообще не было буферизации. - person K-ballo; 21.09.2011
comment
Можете ли вы привести текст стандарта C, подтверждающий это представление? (Я считаю, что это неверно, но у меня нет моей копии стандарта C, чтобы проверить.) И буферизация, конечно, не просто оптимизация; стандарт охватывает многие аспекты буферизации (например, fflush, setbuf и т. д.). - person James Kanze; 21.09.2011

Да; fseek() гарантирует, что файл будет выглядеть так, как он должен, в соответствии с fwrite() выполненными вами операциями.

Стандарт C, ISO/IEC 9899:1999 §7.19.9.2 fseek(), гласит:

Функция fseek устанавливает индикатор позиции файла для потока, на который указывает stream. Если возникает ошибка чтения или записи, устанавливается индикатор ошибки для потока, и fseek завершается ошибкой.

person Jonathan Leffler    schedule 21.09.2011
comment
На самом деле он спрашивает о fseek(). - person K-ballo; 21.09.2011
comment
Учитывая текст вашего ответа и процитированный раздел, вы говорите, что fseek должен делать эквивалент fflush? Мне было не совсем понятно. - person CB Bailey; 21.09.2011

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

person CB Bailey    schedule 21.09.2011

Кажется, что вас действительно беспокоит то, не окажутся ли ранее записанные (но еще не сброшенные) данные в неправильном месте в файле, если вы сделаете fseek.

Нет, этого не произойдет. Он будет вести себя так, как вы ожидаете.

person NPE    schedule 21.09.2011

У меня есть смутные воспоминания о требовании, чтобы вы вызывали fflush перед fseek, но у меня нет моей копии стандарта C, доступной для проверки. (Если вы этого не сделаете, это будет неопределенное поведение или определенная реализация или что-то в этом роде.) Общий стандарт Unix указывает, что:

Если самой последней операцией, отличной от ftell(), в данном потоке является fflush(), смещение файла в базовом описании открытого файла должно быть скорректировано, чтобы отразить местоположение, указанное fseek().

[...]

Если поток доступен для записи, а буферизованные данные не были записаны в базовый файл, fseek() должна вызвать запись незаписанных данных в файл и пометить поля st_ctime и st_mtime файла для обновления.

Однако это помечено как расширение стандарта ISO C, поэтому вы не можете рассчитывать на это, кроме как на платформах Unix (или других платформах, которые дают аналогичные гарантии).

person James Kanze    schedule 21.09.2011
comment
рассмотрим, например, 7.19.5.3/6: вывод не должен следовать непосредственно за вводом без промежуточного вызова функции fflush или функции позиционирования файла (fseek, fsetpos или перемотка назад). Это не является окончательным, но если бы требовалось вызывать fflush после вывода и перед fseek, то это упоминание fseek было бы излишним, так как сброс все равно был бы. - person Steve Jessop; 21.09.2011
comment
@Steve Это может быть ограничение, о котором я думал - как я уже сказал, я смутно помню требование вызывать fflush, но у меня нет под рукой моей копии стандарта, чтобы проверить, где это был (и поскольку я обычно использую только ввод-вывод C++, я не помню активно ввод-вывод в стиле C). - person James Kanze; 21.09.2011