Поделиться через


Функция WriteFile (fileapi.h)

Записывает данные в указанный файл или на устройство ввода-вывода.

Эта функция предназначена как для синхронных, так и для асинхронных операций. Аналогичную функцию, предназначенную исключительно для асинхронных операций, см. в разделе WriteFileEx.

Синтаксис

BOOL WriteFile(
  [in]                HANDLE       hFile,
  [in]                LPCVOID      lpBuffer,
  [in]                DWORD        nNumberOfBytesToWrite,
  [out, optional]     LPDWORD      lpNumberOfBytesWritten,
  [in, out, optional] LPOVERLAPPED lpOverlapped
);

Параметры

[in] hFile

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

Параметр hFile должен быть создан с доступом на запись. Дополнительные сведения см. в разделах Универсальные права доступа и Безопасность файлов и права доступа.

Для асинхронных операций записи hFile может быть любым дескриптором, открытым с помощью функции CreateFile с помощью флага FILE_FLAG_OVERLAPPED или дескриптора сокета или функцииaccept .

[in] lpBuffer

Указатель на буфер, содержащий данные для записи в файл или устройство.

Этот буфер должен оставаться действительным в течение операции записи. Вызывающий объект не должен использовать этот буфер до завершения операции записи.

[in] nNumberOfBytesToWrite

Число байтов, записываемых в файл или устройство.

Нулевое значение указывает операцию записи null. Поведение операции записи null зависит от базовой файловой системы или технологии связи.

Windows Server 2003 и Windows XP: Операции записи канала в сети ограничены по размеру на запись. Количество зависит от платформы. Для платформ x86 это 63,97 МБ. Для 64-разрядных платформ это 31,97 МБ. Для Itanium это 63,95 МБ. Дополнительные сведения о канале см. в разделе Примечания.

[out, optional] lpNumberOfBytesWritten

Указатель на переменную, которая получает количество байтов, записанных при использовании синхронного параметра hFile . Перед выполнением какой-либо работы или проверки ошибок в файле WriteFile это значение равно нулю. Используйте значение NULL для этого параметра, если это асинхронная операция, чтобы избежать потенциально ошибочных результатов.

Этот параметр может иметь значение NULL , только если параметр lpOverlapped не равен NULL.

Windows 7: Этот параметр не может иметь значение NULL.

Дополнительные сведения см. в разделе «Примечания».

[in, out, optional] lpOverlapped

Указатель на структуру OVERLAPPED требуется, если параметр hFile был открыт с FILE_FLAG_OVERLAPPED, в противном случае этот параметр может иметь значение NULL.

Для файла hFile , поддерживающего смещение байтов, при использовании этого параметра необходимо указать смещение байтов, с которого начинается запись в файл или устройство. Это смещение задается путем задания элементов Offset и OffsetHigh структуры OVERLAPPED . Для файла hFile , который не поддерживает смещения байтов, offset и OffsetHigh игнорируются.

Для записи в конец файла укажите элементы Offset и OffsetHigh структуры OVERLAPPED как 0xFFFFFFFF. Это функционально эквивалентно вызову функции CreateFile для открытия hFile с помощью FILE_APPEND_DATA доступа.

Дополнительные сведения о различных сочетаниях lpOverlapped и FILE_FLAG_OVERLAPPED см. в разделах Примечания и Синхронизация и положение файлов .

Возвращаемое значение

Если функция выполнена успешно, возвращается ненулевое значение (TRUE).

Если функция завершается асинхронно, возвращаемое значение равно нулю (FALSE). Чтобы получить расширенные сведения об ошибке, вызовите функцию GetLastError .

ПримечаниеERROR_IO_PENDING кода GetLastError не является ошибкой; он указывает, что операция записи ожидает завершения асинхронно. Дополнительные сведения см. в подразделе "Примечания".
 

Комментарии

Функция WriteFile возвращается при возникновении одного из следующих условий:

  • Число запрошенных байтов записывается.
  • Операция чтения освобождает буферное пространство в конце канала чтения (если запись была заблокирована). Дополнительные сведения см. в разделе Каналы .
  • Используется асинхронный дескриптор, а запись выполняется асинхронно.
  • Происходит ошибка.
Функция WriteFile может завершиться сбоем при ERROR_INVALID_USER_BUFFER или ERROR_NOT_ENOUGH_MEMORY при наличии слишком большого количества невыполненных асинхронных запросов ввода-вывода.

Чтобы отменить все ожидающие асинхронные операции ввода-вывода, используйте один из следующих способов:

  • CancelIo — эта функция отменяет только операции, выданные вызывающим потоком для указанного дескриптора файла.
  • CancelIoEx — эта функция отменяет все операции, выполняемые потоками для указанного дескриптора файла.
Используйте функцию CancelSynchronousIo для отмены ожидающих синхронных операций ввода-вывода.

Операции ввода-вывода, отмененные с ошибкой ERROR_OPERATION_ABORTED.

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

Если часть файла заблокирована другим процессом, а операция записи перекрывает заблокированную часть, WriteFile завершается ошибкой.

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

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

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

Система интерпретирует ноль байтов для записи как указывающую операцию записи null, и WriteFile не усекает и не расширяет файл. Чтобы усечь или расширить файл, используйте функцию SetEndOfFile .

Символы можно записать в буфер экрана с помощью WriteFile с дескриптором для вывода консоли. Точное поведение функции определяется режимом консоли. Данные записываются в текущее положение курсора. Позиция курсора обновляется после операции записи. Дополнительные сведения о дескрипторов консоли см. в разделе CreateFile.

При записи на устройство связи поведение WriteFile определяется текущим временем ожидания связи, которое устанавливается и извлекается с помощью функций SetCommTimeouts и GetCommTimeouts . Если не задать значения времени ожидания, могут возникнуть непредсказуемые результаты. Дополнительные сведения об истечении времени ожидания связи см. в разделе COMMTIMEOUTS.

Хотя запись в одном секторе является атомарной, много секторная запись не гарантируется, что она будет атомарной, если вы не используете транзакцию (т. е. созданный дескриптор представляет собой транзакционный дескриптор; например, дескриптор, созданный с помощью CreateFileTransacted). Кэшированные записи в нескольких секторах не всегда могут быть записаны на диск сразу; Поэтому укажите FILE_FLAG_WRITE_THROUGH в CreateFile , чтобы обеспечить запись всей много секторной записи на диск без потенциальных задержек кэширования.

При записи непосредственно в том с подключенной файловой системой необходимо сначала получить монопольный доступ к тому. В противном случае вы рискуете привести к повреждению данных или нестабильной работе системы, так как операции записи приложения могут конфликтовать с другими изменениями, поступающими из файловой системы, и оставить содержимое тома в несогласованном состоянии. Чтобы избежать этих проблем, в Windows Vista и более поздних версиях были внесены следующие изменения:

  • Запись в дескриптор тома будет выполнена успешно, если на томе нет подключенной файловой системы или если выполняется одно из следующих условий:
    • Секторы, в которые необходимо записать, являются загрузочными секторами.
    • Секторы, которые необходимо записать, находятся за пределами пространства файловой системы.
    • Вы явно заблокировали или отключили том с помощью FSCTL_LOCK_VOLUME или FSCTL_DISMOUNT_VOLUME.
    • В томе нет фактической файловой системы. (Иными словами, в ней подключена файловая система RAW.)
  • Запись на дескриптор диска будет выполнена успешно, если выполняется одно из следующих условий:
    • Секторы, для записи в которые не попадают в экстенты тома.
    • Секторы, которые необходимо записать в подключенный том, но вы явно заблокировали или отключили том с помощью FSCTL_LOCK_VOLUME или FSCTL_DISMOUNT_VOLUME.
    • Секторы, записываемые в том, не имеют подключенной файловой системы, кроме RAW.
Существуют строгие требования для успешной работы с файлами, открытыми с помощью CreateFile с помощью FILE_FLAG_NO_BUFFERING. Дополнительные сведения см. в разделе Буферизация файлов.

Если hFile был открыт с помощью FILE_FLAG_OVERLAPPED, действуют следующие условия:

  • Параметр lpOverlapped должен указывать на допустимую и уникальную структуру OVERLAPPED , в противном случае функция может неправильно сообщить о завершении операции записи.
  • Параметр lpNumberOfBytesWritten должен иметь значение NULL. Чтобы получить количество записанных байтов, используйте функцию GetOverlappedResult . Если параметр hFile связан с портом завершения ввода-вывода, можно также получить количество записанных байтов, вызвав функцию GetQueuedCompletionStatus .
В Windows Server 2012 эта функция поддерживается следующими технологиями.
Технология Поддерживается
Протокол SMB 3.0 Да
Прозрачная отработка отказа (TFO) SMB 3.0 Да
SMB 3.0 с масштабируемыми общими папками (SO) Да
Файловая система общего тома кластера (CSVFS) Да
Восстанавливаемая файловая система (ReFS) Да
 

Синхронизация и положение файлов

Если hFile открывается с помощью FILE_FLAG_OVERLAPPED, это асинхронный дескриптор файла; в противном случае он является синхронным. Правила использования структуры OVERLAPPED немного отличаются для каждой из них, как отмечалось ранее.
Примечание Если файл или устройство открывается для асинхронного ввода-вывода, последующие вызовы функций, таких как WriteFile с использованием этого дескриптора, обычно возвращаются немедленно, но также могут работать синхронно в отношении заблокированного выполнения. Для получения дополнительной информации см. http://support.microsoft.com/kb/156932.
 
Рекомендации по работе с асинхронными дескрипторами файлов:
  • WriteFile может вернуться до завершения операции записи. В этом сценарии WriteFile возвращает значение FALSE , а функция GetLastError возвращает ERROR_IO_PENDING, что позволяет продолжить вызывающий процесс, пока система завершит операцию записи.
  • Параметр lpOverlapped не должен иметь значение NULL и должен использоваться со следующими фактами:
    • Хотя событие, указанное в структуре OVERLAPPED , устанавливается и сбрасывается системой автоматически, смещение, указанное в структуре OVERLAPPED , не обновляется автоматически.
    • WriteFile сбрасывает событие до состояния без знака при начале операции ввода-вывода.
    • Событие, указанное в структуре OVERLAPPED , устанавливается в сигнальное состояние после завершения операции записи; до этого времени операция записи считается ожидающей.
    • Так как операция записи начинается с смещения, указанного в структуре OVERLAPPED , и WriteFile может вернуться до завершения операции записи на уровне системы (ожидание записи), ни смещение, ни какая-либо другая часть структуры не должны изменяться, освобождаться или повторно использоваться приложением до тех пор, пока не будет показано событие (т. е. запись завершается).
Рекомендации по работе с синхронными дескрипторами файлов:
  • Если lpOverlapped имеет значение NULL, операция записи начинается в текущей позиции файла, а WriteFile не возвращается, пока операция не будет завершена, а система обновит указатель на файл до возврата WriteFile .
  • Если значение lpOverlapped не равно NULL, операция записи начинается со смещением, указанным в структуре OVERLAPPED , и WriteFile не возвращается до завершения операции записи. Система обновляет поля OVERLAPPED Internal и InternalHigh, а также указатель на файл перед возвратом WriteFile .
Дополнительные сведения см. в разделах CreateFile и Синхронный и асинхронный ввод-вывод.

Трубы

Если используется анонимный канал и дескриптор чтения закрыт, при попытке writeFile выполнить запись с помощью соответствующего дескриптора записи в канале функция возвращает значение FALSE , а GetLastError возвращает ERROR_BROKEN_PIPE.

Если буфер канала заполнен, когда приложение использует функцию WriteFile для записи в канал, операция записи может завершиться не сразу. Операция записи будет завершена, когда операция чтения (с помощью функции ReadFile ) предоставит больше системного буферного пространства для канала.

При записи в неблокирующий дескриптор канала в режиме байтов с недостаточным буферным пространством WriteFile возвращает значение TRUE с *lpNumberOfBytesWritten<nNumberOfBytesToWrite.

Дополнительные сведения о канале см. в разделе Каналы.

Транзакция операций

При наличии транзакции, привязанной к дескриптору файла, выполняется транзакция записи файла. Дополнительные сведения см. в разделе Сведения о транзакционной NTFS.

Примеры

Некоторые примеры см. в разделах Создание и использование временного файла и Открытие файла для чтения или записи.

В следующем примере C++ показано, как выравнивать секторы для операций записи небуферированных файлов. Переменная Size — это размер исходного блока данных, который требуется записать в файл. Дополнительные правила, касающиеся небуферированных файловых операций ввода-вывода, см. в разделе Буферизация файлов.
#include <windows.h>

#define ROUND_UP_SIZE(Value,Pow2) ((SIZE_T) ((((ULONG)(Value)) + (Pow2) - 1) & (~(((LONG)(Pow2)) - 1))))

#define ROUND_UP_PTR(Ptr,Pow2)  ((void *) ((((ULONG_PTR)(Ptr)) + (Pow2) - 1) & (~(((LONG_PTR)(Pow2)) - 1))))

int main()
{
   // Sample data
   unsigned long bytesPerSector = 65536; // obtained from the GetFreeDiskSpace function.
   unsigned long size = 15536; // Buffer size of your data to write.
   
   // Ensure you have one more sector than Size would require.
   size_t sizeNeeded = bytesPerSector + ROUND_UP_SIZE(size, bytesPerSector);
   
   // Replace this statement with any allocation routine.
   auto buffer = new uint8_t[SizeNeeded];
   
   // Actual alignment happens here.
   auto bufferAligned = ROUND_UP_PTR(buffer, bytesPerSector);

   // ... Add code using bufferAligned here.
   
   // Replace with corresponding free routine.
   delete buffer;
}

Требования

   
Минимальная версия клиента Windows XP [классические приложения | Приложения UWP]
Минимальная версия сервера Windows Server 2003 [классические приложения | Приложения UWP]
Целевая платформа Windows
Header fileapi.h (включая Windows.h)
Библиотека Kernel32.lib
DLL Kernel32.dll

См. также

CancelIo

CancelIoEx

CancelSynchronousIo

CreateFile

CreateFileTransacted

Функции управления файлами

Getlasterror

GetOverlappedResult

GetQueuedCompletionStatus

ReadFile

SetEndOfFile

WriteFileEx