Функция 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
Дескриптор устройства ввода-вывода или файла (например, файл, поток файлов, физический диск, том, буфер консоли, ленточный диск, сокет, ресурс связи, mailslot или канал).
Необходимо создать параметр hFile с доступом на запись. Дополнительные сведения см. в
Для асинхронных операций записи
[in] lpBuffer
Указатель на буфер, содержащий данные, записываемые в файл или устройство.
Этот буфер должен оставаться допустимым в течение операции записи. Вызывающий объект не должен использовать этот буфер до завершения операции записи.
[in] nNumberOfBytesToWrite
Количество байтов, записываемых в файл или устройство.
Значение нуля указывает операцию записи NULL. Поведение операции записи null зависит от базовой файловой системы или технологии связи.
Windows Server 2003 и Windows XP: операции записи канала в сети ограничены размером на запись. Сумма зависит от платформы. Для платформ x86 это 63,97 МБ. Для платформ x64 это 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, поддерживающей смещение байтов, если этот параметр используется, необходимо указать смещение байтов, с которого начинается запись в файл или устройство. Это смещение задается путем задания
Чтобы записать в конец файла, укажите
Дополнительные сведения о различных сочетаниях lpOverlapped и FILE_FLAG_OVERLAPPEDсм. в разделе "Примечания" и разделе синхронизации и положения файлов.
Возвращаемое значение
Если функция выполнена успешно, возвращаемое значение ненулевое (TRUE).
Если функция завершается сбоем или выполняется асинхронно, возвращаемое значение равно нулю (FALSE). Чтобы получить расширенные сведения об ошибке, вызовите функцию getLastError
Замечания
Функция WriteFile возвращается при возникновении одного из следующих условий:
- Число запрошенных байтов записывается.
- Операция чтения освобождает буферное пространство в конце канала чтения (если запись была заблокирована). Дополнительные сведения см. в разделе каналов
. - Используется асинхронный дескриптор и выполняется запись асинхронно.
- Возникает ошибка.
Чтобы отменить все ожидающие асинхронные операции ввода-вывода, используйте следующие действия:
- CancelIo— эта функция отменяет только операции, выданные вызывающим потоком для указанного дескриптора файла.
- CancelIoEx— эта функция отменяет все операции, выданные потоками для указанного дескриптора файла.
Операции ввода-вывода, которые отменяются вместе с ошибкой 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 и более поздних версиях были внесены следующие изменения:
- Запись на дескриптор тома будет выполнена успешно, если том не имеет подключенной файловой системы или если одно из следующих условий имеет значение true:
- Секторы, которые должны быть записаны, являются загрузочными секторами.
- Секторы, которые должны быть записаны для размещения за пределами пространства файловой системы.
- Вы явно заблокировали или отключили том с помощью FSCTL_LOCK_VOLUME или FSCTL_DISMOUNT_VOLUME.
- Том не имеет фактической файловой системы. (Другими словами, она подключена к файловой системе RAW.)
- Запись на дескриптор диска будет выполнена успешно, если одно из следующих условий имеет значение true:
- Секторы, которые должны быть записаны, чтобы не попасть в экстенты тома.
- Секторы, которые необходимо записать в подключенный том, но вы явно заблокировали или отключили том с помощью FSCTL_LOCK_VOLUME или FSCTL_DISMOUNT_VOLUME.
- Секторы, которые необходимо записать в том, который не подключен к файловой системе, кроме RAW.
Если hFile был открыт с помощью FILE_FLAG_OVERLAPPED, в силу применяются следующие условия:
- Параметр lpOverlapped должен указывать на допустимую и уникальную структуру OVERLAPPED, в противном случае функция может неправильно сообщить о завершении операции записи.
- Параметр
lpNumberOfBytesWritten должен иметь значение NULL . Чтобы получить количество записанных байтов, используйте функцию GetOverlappedResult. Если параметр hFile связан с портом завершения ввода-вывода, можно также получить количество байтов, записанных путем вызова функции GetQueuedCompletionStatus.
Технологии | Поддержанный |
---|---|
Протокол SMB 3.0 | Да |
Отработка отказа SMB 3.0 (TFO) | Да |
SMB 3.0 с масштабируемыми общими папками (SO) | Да |
Файловая система общего тома кластера (CSVFS) | Да |
Отказоустойчивая файловая система (ReFS) | Да |
синхронизации и положения файлов
Если hFile открыт с FILE_FLAG_OVERLAPPED, это асинхронный дескриптор файла; в противном случае она синхронна. Правила использования ПЕРЕКРЫТИЯ структуры немного отличаются для каждой из них, как отмечалось ранее.- WriteFile может вернуться до завершения операции записи. В этом сценарии WriteFile возвращает false, а функция GetLastError getLastError возвращает ERROR_IO_PENDING, что позволяет вызывать процесс продолжения, пока система завершает операцию записи.
- Параметр lpOverlapped не должен быть null и должен использоваться со следующими фактами.
- Несмотря на то, что событие, указанное в структуре
OVERLAPPED, устанавливается и сбрасывается автоматически системой, смещение, указанное в структуре OVERLAPPED , не обновляется автоматически. - WriteFile сбрасывает событие в незначаемое состояние при запуске операции ввода-вывода.
- Событие, указанное в структуре OVERLAPPED, имеет сигнальное состояние при завершении операции записи; до этого времени операция записи считается ожидающей.
- Так как операция записи начинается с смещения, указанного в структуре OVERLAPPED, и WriteFile может вернуться до завершения операции записи на уровне системы (ожидающая запись), ни смещение, ни любая другая часть структуры не должна быть изменена, освобождена или повторно использована приложением, пока событие не будет сигнализировать (то есть, завершение записи).
- Несмотря на то, что событие, указанное в структуре
- Если lpOverlappedNULL, операция записи начинается с текущей позиции файла и WriteFile не возвращается до завершения операции, а система обновляет указатель файла до возврата WriteFile.
- Если lpOverlapped не NULL, операция записи начинается с смещения, указанного в структуре OVERLAPPED и WriteFile не возвращается до завершения операции записи. Система обновляет поля OVERLAPPED внутренних и внутренних хиг и указатель файла перед возвратом WriteFile.
каналы
Если используется анонимный канал и дескриптор чтения был закрыт, когда WriteFile пытается написать с помощью соответствующего дескриптора записи канала, функция возвращает FALSE и GetLastError возвращает ERROR_BROKEN_PIPE.Если буфер канала заполнен, когда приложение использует функцию WriteFile для записи в канал, операция записи может не завершиться немедленно. Операция записи будет завершена, когда операция чтения (с помощью функции ReadFile) делает больше системного буферного пространства для канала.
При записи в неблокирующий дескриптор канала в режиме байтов с недостаточным пространством буфера WriteFile возвращает TRUE с *lpNumberOfBytesWritten<nNumberOfBytesToWrite.
Дополнительные сведения о каналах см. в разделе Трубы.
операции с транзакцией
Если транзакция привязана к дескриптору файла, то запись файла выполняется. Дополнительные сведения см. в разделе About Transactional NTFS.Примеры
Примеры см. в статье Создание и использование временного файла и открытие файла для чтения или записи.
В следующем примере C++ показано, как выровнять секторы для небуферированных операций записи файлов. Переменная размера — это размер исходного блока данных, который вы хотите записать в файл. Дополнительные правила, касающиеся небуферированных операций ввода-вывода файлов, см. в буферизации файлов.#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] |
целевая платформа | Виндоус |
заголовка | fileapi.h (включая Windows.h) |
библиотеки |
Kernel32.lib |
DLL | Kernel32.dll |