WRITE(2) | Руководство программиста Linux | WRITE(2) |
write - запись в файловый дескриптор
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
Вызов write() пишет до count байт из буфера, начиная с buf, в файл, на который ссылается файловый дескриптор fd.
Количество записанных байт может быть меньше чем count если, например, недостаточно места на физическом носителе, или исчерпан отведённый лимит ресурса RLIMIT_FSIZE (см. setrlimit(2)), или вызов был прерван обработчиком сигналов после уже записанных меньше чем count байт. (См. также pipe(7).)
В случае с файлами, разрешающими позиционирование (т.е., к которым можно применить lseek(2), например, обычные файлы), запись производится по текущему файловому смещению, а смещение файла увеличивается на реальное число записанных байт. Если файл был открыт с помощью open(2) с аргументом O_APPEND, то перед записью файловое смещение устанавливается в конец файла. Согласование файлового смещения и операции записи выполняются атомарно.
В POSIX требуется, чтобы read(2), который может быть вызван сразу после write(), возвращал новые данные. Заметим, что не все файловые системы соответствуют стандарту POSIX.
В соответствие с POSIX.1, если count больше SSIZE_MAX, то результат зависит от реализации; смотрите ЗАМЕЧАНИЯ по верхнему пределу в Linux.
При успешном выполнении возвращается количество записанных байт. При ошибке возвращается -1 и errno устанавливается в соответствующее значение.
Заметим, что при успешном выполнении write() может передать меньше чем count байт. Такая частичная запись может возникать по нескольким причинам; например, из-за недостаточного количества места на диске, на который пишутся все запрошенные байты или из-за прерывания блокировки write() сокета, канала или подобного обработчиком сигнала после частичной передачи, но до того, как были переданы все запрашиваемый байты. При даже частичной записи вызывающий может запустить другой вызов write() для передачи оставшихся байт. Последующий вызов или передаст остальные байты, или может завершиться ошибкой (например, если переполнен диск).
Если count равен нулю и fd указывает на обычный файл, то write() может вернуть ошибку, если обнаружена одна из перечисленных ниже ошибок. Если ошибок не обнаружено или проверка ошибки не производилась, то возвращается 0 без каких-либо других последствий. Если count равен нулю и fd указывает на отличный от обычного файл, то результат не определён.
В зависимости от объекта, на который указывает fd, могут происходить и другие ошибки.
SVr4, 4.3BSD, POSIX.1-2001.
Согласно SVr4, запись может быть прервана в любом месте (с возвратом EINTR), а не только перед тем как будут записаны какие-либо данные.
Типы данных size_t и ssize_t представляют собой, соответственно, беззнаковый и знаковый целочисленный тип, определены в POSIX.1.
Успешный возврат из вызова write() не даёт никаких гарантий, что данные сохранены на диске. В некоторых файловых системах, включая NFS, даже не гарантируется, что для данных было зарезервировано место. В этом случае некоторые ошибки могут появиться только в будущем write(2), fsync(2) или даже close(2). Единственный способ получить гарантированную запись — вызвать fsync(2) после записи всех данных.
Если write() прерван обработчиком сигналов до начала записи, то вызов возвращает ошибку EINTR; если он прерван после начала записи, то вызов считается успешным, и возвращается число записанных байт.
В Linux write() (и похожие системные вызовы) передаст не больше 0x7ffff000 (2 147 479 552) байт, возвращая число байт, переданных на самом деле (это утверждение справедливо как к 32-битным, так и к 64-битным системам).
Возвращаемое значение ошибки при выполнении write() прямого ввода-вывода не означает ошибки записи целиком. Данные могут быть записаны частично, а по смещению в файле, на котором write() остановился, данные должны считаться некорректными.
В соответствие с POSIX.1-2008/SUSv4 раздел XSI 2.9.7 ("Thread Interactions with Regular File Operations"):
Среди перечисленных в программном интерфейсе есть write() и writev(2). И среди действий, которые должны выполняться атомарно между нитями (и процессами), если обновление файлового смещения. Однако в Linux до версии 3.14 это было не так: если два процесса с общим открытым файловым описанием (смотрите open(2)) выполняют write() (или writev(2)) одновременно, то операции ввода-вывода не атомарны при обновлении файлового смещения; в результате записанные двумя процессами блоки данных могут (некорректно) перекрываться. Эта ошибка исправлена в Linux 3.14.
close(2), fcntl(2), fsync(2), ioctl(2), lseek(2), open(2), pwrite(2), read(2), select(2), writev(2), fwrite(3)
2019-03-06 | Linux |