ОБЗОР
#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.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
В случае успеха, возвращается количество записанных байт (ноль говорит о том, что ничего записано не было). Это число может быть меньше, чем количество запрошенных байт, данная ситуация не является ошибкой; такое может происходить, например, в случае переполнения дискового пространства. Также см. ПРИМЕЧАНИЯ.В случае ошибки возвращается -1 и значение errno устанавливается соответствующим образом.
Если count равен нулю и fd указывает на обычный файл, то write() может вернуть ошибку, если обнаружена одна из перечисленных ниже ошибок. Если ошибок не обнаружено или проверка ошибки не производилась, то возвращается 0 без каких-либо других последствий. Если count равен нулю и fd указывает на отличный от обычного файл, то результат не определён.
ОШИБКИ
- EAGAIN
- Файловый дескриптор fd указывает на файл, не являющийся сокетом и помеченный как неблокирующий ввод/вывод (O_NONBLOCK), а запись вызовет блокировку. См. open(2) для дальнейшей информации по флагу O_NONBLOCK.
- EAGAIN или EWOULDBLOCK
- Файловый дескриптор fd указывает на сокет, который помечен как неблокирующий ввод/вывод (O_NONBLOCK), а запись вызовет блокировку. По POSIX.1-2001 разрешено возвращать ошибку в обоих случая и не требуется, чтобы эти константы имели одно значение, поэтому переносимые приложения должны проверять обе причины.
- EBADF
- Значение fd не является правильным файловым дескриптором или он не открыт для записи.
- EDESTADDRREQ
- Значение fd ссылается на сокет дейтаграмм, у которого с помощью connect(2) не назначен адрес другой стороны.
- EDQUOT
- Исчерпана пользовательская квота на дисковые блоки файловой системы с файлом, на который указывает fd.
- EFAULT
- buf находится за пределами доступного вам адресного пространства.
- EFBIG
- Попытка записать в файл, который превышает заданное при реализации ограничение на размер файла или ограничение на размер файла для текущего процесса, или запись в позицию после максимально разрешённого смещения.
- EINTR
- Этот вызов был прерван сигналом, перед тем как были записаны какие-либо данные; см signal(7).
- EINVAL
- fd присоединён к объекту, который не подходит для записи; или файл был открыт с указанием флага O_DIRECT, или неправильно выравнено адрес в buf, значение count или текущее файловое смещение.
- EIO
- Во время изменения индексного дескриптора (inode) возникла низкоуровневая ошибка ввода/вывода.
- ENOSPC
- На устройстве, содержащем файл, на который ссылается fd, нет свободного места.
- EPERM
- Выполнение операции предотвращено опечатыванием (file seal); смотрите fcntl(2).
- EPIPE
- fd ссылается на конвейер или сокет, у которого закрыто чтение. Когда такое случается, пишущий процесс также получит сигнал SIGPIPE. (Таким образом, возвращаемое значение можно будет увидеть только если программа перехватывает, блокирует или игнорирует этот сигнал.)
В зависимости от объекта, на который указывает fd, могут происходить и другие ошибки.
СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4, 4.3BSD, POSIX.1-2001.Согласно SVr4, запись может быть прервана в любом месте (с возвратом EINTR), а не только перед тем как будут записаны какие-либо данные.
ЗАМЕЧАНИЯ
Успешный возврат из вызова write() не даёт никаких гарантий, что данные сохранены на диске. Фактически, в некоторых ошибочных реализациях даже нет гарантии, что для данных было зарезервировано место. Единственный способ получить гарантированную запись --- вызвать fsync(2) после записи всех данных.Если write() прерван обработчиком сигналов до начала записи, то вызов возвращает ошибку EINTR; если он прерван после начала записи, то вызов считается успешным, и возвращается число записанных байт.
В Linux write() (и похожие системные вызовы) передаст не больше 0x7ffff000 (2 147 479 552) байт, возвращая число байт, переданных на самом деле (это утверждение справедливо как к 32-битным, так и к 64-битным системам).
ДЕФЕКТЫ
В соответствие с POSIX.1-2008/SUSv4 раздел XSI 2.9.7 ("Thread Interactions with Regular File Operations"):
- Следующие функции должны выполняться атомарно по отношению друг к другу, чтобы работать с обычными файлами или символическими ссылками так, как указано в POSIX.1-2008: …
Среди перечисленных в программном интерфейсе есть write() и writev(2). И среди действий, которые должны выполняться атомарно между нитями (и процессами), если обновление файлового смещения. Однако в Linux до версии 3.14 это было не так: если два процесса с общим открытым файловым описанием (смотрите open(2)) выполняют write() (или writev(2)) одновременно, то операции ввода-вывода не атомарны при обновлении файлового смещения; в результате записанные двумя процессами блоки данных могут (некорректно) перекрываться. Эта ошибка исправлена в Linux 3.14.