данные будут записаны в конец файла, даже если текущее смещение было восстановлено с помощью
lseek
.
Современные системы предоставляют дополнительные флаги с более специализированным назначением. Они кратко описаны в табл. 4.8.
Таблица 4.8. Дополнительные расширенные флаги POSIX для
open
Флаг
Значение
O_APPEND
Принудительно осуществляет все записи в конец файла
O_CREAT
Создает новый файл, если он не существует.
O_EXCL
При использовании вместе с
O_CREAT
возвращает ошибку, если файл уже существует
O_TRUNC
Урезает файл (устанавливает его длину в 0), если он существует.
Флаги
O_DSYNC
,
O_RSYNC
и
O_SYNC
требуют некоторых пояснений. Системы Unix (включая Linux) содержат внутренний кэш дисковых блоков, который называется буферным кэшем (buffer cache). Когда возвращается системный вызов
write
, данные, переданные операционной системе, были скопированы в буфер в буферном кэше. Они необязательно были записаны на диск.
Буферный кэш значительно повышает производительность: поскольку дисковый ввод/ вывод часто на порядок и медленнее операций центрального процессора и памяти, программы значительно снизили бы производительность, если бы им пришлось ждать завершения каждой записи на диск. Вдобавок, если данные были недавно записаны на диск, при последующем чтении тех же данных они уже находились бы в буферном кэше, откуда их можно вернуть немедленно, не дожидаясь завершения операции чтения с диска.
Системы Unix осуществляют также опережающее чтение; поскольку чтение в большинстве случаев последовательное, операционная система после прочтения одного блока осуществляет чтение нескольких дополнительных последовательных блоков таким образом, что эта информация будет уже находиться в кэше, когда программа ее запросит. Если один и тот же файл читают несколько программ, они все получают преимущество, поскольку все получают свои данные из одной копии дисковых блоков файла в буферном кэше.
Все это кэширование, конечно, замечательно, но бесплатного обеда не бывает. В то время, пока данные находятся в буферном кэше и до того, как они будут записаны на диск, есть небольшое, но вполне реальное окно, в котором может случиться катастрофа; например, если выключат питание. Современные дисковые приводы обостряют эту проблему: у многих из них есть собственные внутренние буферы, поэтому при записи данных на диск они могут оказаться не записанными на носитель при выключении питания! Это может быть значительной проблемой для небольших систем, которые не находятся в информационном центре с контролируемым энергоснабжением или не имеют источников бесперебойного питания (UPS). [50]
50
Если у вас нет UPS и вы используете систему для критической работы, мы настоятельно рекомендуем вам обзавестись им. Следует также регулярно делать резервные копии. — Примеч. автора.
Для
большинства приложений вероятность того, что данные в буферном кэше могут быть нечаянно потеряны, довольно низка. Однако, для некоторых приложений любой такой шанс неприемлем. Поэтому в системе Unix было введено понятие синхронного ввода/вывода, при котором программе гарантируется, что по возвращении из системного вызова данные безопасно записаны на физическое устройство хранения.
Флаг
O_DSYNC
гарантирует целостность данных; данные и любая другая информация, которую операционная система должна найти, записываются на диск до возвращения
write
. Однако, вспомогательные данные, такие, как время модификации или доступа к файлу, могут быть не записаны на диск. Флаг
O_SYNC
требует, чтобы эти данные также были записаны на диск до возвращения
write
. (Здесь тоже нет бесплатного обеда; синхронные записи могут серьезно повлиять на производительность программы, заметно ее снизив.)
Флаг
O_RSYNC
предназначен для чтения данных: если
read
находит данные в буферном кэше, которые были назначены для записи на диск, функция не вернет эти данные до тех пор, пока они не будут записаны. Два других флага влияют на это: в частности,
O_SYNC
заставит
read
ждать, пока не будут также записаны и вспомогательные данные.
ЗАМЕЧАНИЕ. Что касается ядра версии 2.4, Linux рассматривает все три флага одинаково со значением флага
O_SYNC
. Более того, Linux определяет дополнительные флаги, которые специфичны для Linux и предназначены для специального использования. Дополнительные подробности см. в справочной странице GNU/Linux для open(2).
4.7. Форсирование записи данных на диск
Ранее мы описали флаги
O_DSYNC
,
O_RSYNC
и
O_SYNC
для
open
. Мы отметили, что использование этих флагов может замедлить программу, поскольку
write
не возвращается до тех пор, пока все данные не будут записаны на физический носитель.
Со слегка более высоким уровнем риска мы можем сами испечь свое пирожное и съесть его. Это осуществляется путем открытия файла без указания флагов
O_xSYNC
, но с последующим использованием одного из следующих двух системных вызовов в любой момент, когда это необходимо для безопасного перемещения данных на физический носитель:
#include <unistd.h>
int fsync(int fd); /* POSIX FSC */
int fdatasync(int fd); /* POSIX SIO */
Системный вызов
fdatasync
подобен
O_DSYNC
: он форсирует запись данных на конечное физическое устройство. Системный вызов
fsync
подобен
O_SYNC
, форсируя запись на физическое устройство не только данных файла, но и вспомогательных данных. Вызов
fsync
более переносим; он существовал в мире Unix в течение более продолжительного времени, и вероятность его наличия среди широкого ряда систем больше.
Можно использовать эти вызовы с указателями файлов
<stdio.h>
, вызвав сначала
fflush
, а затем
fileno
для получения дескриптора нижележащего файла. Вот функция
fpsync
, которая может использоваться для заключения обеих операций в один вызов. Она возвращает в случае успеха 0: