WriteFile 函数 (fileapi.h)
将数据写入指定的文件或输入/输出(I/O)设备。
此函数适用于同步和异步操作。 有关专为异步操作设计的类似函数,请参阅 WriteFileEx。
语法
BOOL WriteFile(
[in] HANDLE hFile,
[in] LPCVOID lpBuffer,
[in] DWORD nNumberOfBytesToWrite,
[out, optional] LPDWORD lpNumberOfBytesWritten,
[in, out, optional] LPOVERLAPPED lpOverlapped
);
参数
[in] hFile
文件或 I/O 设备的句柄(例如文件、文件流、物理磁盘、卷、控制台缓冲区、磁带驱动器、套接字、通信资源、mailslot 或管道)。
必须使用写入访问权限创建 hFile 参数。 有关详细信息,请参阅 通用访问权限 和 文件安全性和访问权限。
对于异步写入操作,hFile 可以是使用 FILE_FLAG_OVERLAPPED 标志或 套接字 返回的套接字句柄或 接受 函数的 CreateFile 函数打开的任何句柄。
[in] lpBuffer
指向包含要写入文件或设备的数据的缓冲区的指针。
此缓冲区在写入操作的持续时间内必须保持有效。 在写入操作完成之前,调用方不得使用此缓冲区。
[in] nNumberOfBytesToWrite
要写入文件或设备的字节数。
值为零指定 null 写入操作。 null 写入操作的行为取决于基础文件系统或通信技术。
Windows Server 2003 和 Windows XP:网络上的管道写入操作按写入限制大小。 每个平台的金额各不相同。 对于 x86 平台,它为 63.97 MB。 对于 x64 平台,它为 31.97 MB。 对于 Itanium,它为 63.95 MB。 有关管道的详细信息,请参阅“备注”部分。
[out, optional] lpNumberOfBytesWritten
指向使用同步 hFile 参数时写入的字节数的变量的指针。 WriteFile 在执行任何工作或错误检查之前将此值设置为零。 如果这是一个异步操作,请对此参数使用 NULL 以避免潜在的错误结果。
仅当 lpOverlapped 参数不 NULL时,此参数才能 NULL。
Windows 7:此参数不能 NULL。
有关详细信息,请参阅“备注”部分。
[in, out, optional] lpOverlapped
如果使用 FILE_FLAG_OVERLAPPED打开 hFile 参数,则需要指向 OVERLAPPED 结构的指针,否则此参数可以 NULL。
对于支持字节偏移的 hFile,如果使用此参数,则必须指定开始写入文件或设备的字节偏移量。 通过设置 Offset 和 OffsetHighOVERLAPPED 结构的成员来指定此偏移量。 对于不支持字节偏移的 hFile,将忽略 Offset 和 OffsetHigh。
若要写入文件末尾,请将 Offset 和 OffsetHighOVERLAPPED 结构的成员指定为 0xFFFFFFFF。 这在功能上等效于以前调用 CreateFile 函数,以使用 FILE_APPEND_DATA 访问打开 hFile。
有关 lpOverlapped 和 FILE_FLAG_OVERLAPPED的不同组合的详细信息,请参阅“备注”部分和 同步和文件位置 部分。
返回值
如果函数成功,则返回值为非零(TRUE)。
如果函数失败或异步完成,则返回值为零(FALSE)。 若要获取扩展的错误信息,请调用 GetLastError 函数。
言论
发生以下情况之一时,WriteFile 函数返回:
- 所请求的字节数是写入的。
- 读取操作释放管道读取端的缓冲区空间(如果写入被阻止)。 有关详细信息,请参阅 管道 部分。
- 正在使用异步句柄,写入正在异步发生。
- 发生错误。
若要取消所有挂起的异步 I/O 操作,请使用以下任一操作:
- CancelIo— 此函数仅取消由指定文件句柄的调用线程发出的操作。
- CancelIoEx— 此函数将取消指定文件句柄的线程发出的所有操作。
取消的 I/O 操作已完成,错误 ERROR_OPERATION_ABORTED。
WriteFile 函数可能会失败并 ERROR_NOT_ENOUGH_QUOTA,这意味着调用进程的缓冲区无法锁定页。 有关详细信息,请参阅 SetProcessWorkingSetSize。
如果文件的一部分被另一个进程锁定,并且写入操作与锁定部分重叠,WriteFile 失败。
写入文件时,在关闭用于写入的所有句柄之前,最后一次写入时间不会完全更新。 因此,若要确保上次写入时间准确,请在写入文件后立即关闭文件句柄。
在写入操作使用缓冲区时访问输出缓冲区可能会导致从该缓冲区写入的数据损坏。 在写入操作完成之前,应用程序不得写入、重新分配或释放写入操作正在使用的输出缓冲区。 使用异步文件句柄时,这尤其有问题。 有关同步和异步文件句柄的其他信息,请参阅 同步和文件位置 部分以及 同步和异步 I/O。
请注意,远程文件可能无法正确更新时间戳。 若要确保结果一致,请使用无缓冲区 I/O。
系统将零个字节解释为指定 null 写入操作,WriteFile 不会截断或扩展文件。 若要截断或扩展文件,请使用 SetEndOfFile 函数。
可以使用具有控制台输出句柄 WriteFile 将字符写入屏幕缓冲区。 函数的确切行为由控制台模式确定。 数据将写入当前游标位置。 写入操作后将更新游标位置。 有关控制台句柄的详细信息,请参阅 CreateFile。
写入通信设备时,WriteFile 的行为由当前通信超时确定为设置,并使用 SetCommTimeouts 和 GetCommTimeouts 函数进行检索。 如果无法设置超时值,则可能会出现不可预测的结果。 有关通信超时的详细信息,请参阅 COMMTIMEOUTS。
尽管单扇区写入是原子的,但不能保证多扇区写入是原子的,除非使用事务(也就是说,创建的句柄是事务处理句柄;例如,使用 CreateFileTransacted创建的句柄)。 缓存的多扇区写入可能不会始终立即写入磁盘;因此,在 createFile
如果直接写入已装载文件系统的卷,则必须首先获取对该卷的独占访问权限。 否则,可能会造成数据损坏或系统不稳定,因为应用程序的写入可能会与其他来自文件系统的更改冲突,并使卷的内容保持不一致状态。 为防止这些问题,Windows Vista 及更高版本中进行了以下更改:
- 如果卷没有装载的文件系统,或者下列条件之一为 true,则卷句柄上的写入将成功:
- 要写入到的扇区是启动扇区。
- 要写入到的扇区位于文件系统空间之外。
- 已使用 FSCTL_LOCK_VOLUME 或 FSCTL_DISMOUNT_VOLUME显式锁定或卸载卷。
- 卷没有实际的文件系统。 (换句话说,它装载了 RAW 文件系统。
- 如果满足以下条件之一,磁盘句柄上的写入将成功:
- 要写入的扇区不在卷的盘区内。
- 要写入到的扇区位于装载的卷内,但已使用 FSCTL_LOCK_VOLUME 或 FSCTL_DISMOUNT_VOLUME显式锁定或卸载卷。
- 要写入到的扇区位于未装载的文件系统(除 RAW 外)的卷内。
如果使用 FILE_FLAG_OVERLAPPED打开了 hFile,则以下条件有效:
- lpOverlapped 参数必须指向有效的唯一 重叠 结构,否则该函数可能会错误地报告写入操作已完成。
- 应将
lpNumberOfBytesWritten 参数设置为 NULL。 若要获取写入的字节数,请使用 GetOverlappedResult 函数。 如果 hFile 参数与 I/O 完成端口相关联,则还可以通过调用 GetQueuedCompletionStatus 函数来获取写入的字节数。
科技 | 支持 |
---|---|
服务器消息块 (SMB) 3.0 协议 | 是的 |
SMB 3.0 透明故障转移 (TFO) | 是的 |
具有横向扩展文件共享的 SMB 3.0 (SO) | 是的 |
群集共享卷文件系统 (CsvFS) | 是的 |
可复原文件系统 (ReFS) | 是的 |
同步和文件位置
如果使用 FILE_FLAG_OVERLAPPED打开 hFile,则它是异步文件句柄;否则为同步。 如前所述,使用 OVERLAPPED 结构的规则略有不同。- WriteFile 可能会在写入操作完成之前返回。 在此方案中,WriteFile 返回 FALSE,GetLastError 函数返回 ERROR_IO_PENDING,这允许调用进程在系统完成写入操作时继续。
-
lpOverlapped 参数不得 NULL,并且应用于以下事实:
- 尽管系统会自动设置和重置在 OVERLAPPED 结构中指定的事件,但 OVERLAPPED 结构中指定的偏移量不会自动更新。
- WriteFile 在启动 I/O 操作时将事件重置为非对齐状态。
- 写入操作完成后,OVERLAPPED 结构中指定的事件将设置为信号状态;直到该时间,写入操作被视为挂起。
- 由于写入操作从在 OVERLAPPED 结构中指定的偏移量开始,并且 WriteFile 可能会在系统级写入操作完成(写入挂起)之前返回,因此在发出信号之前,应用程序不应修改、释放或重复使用结构的任何其他部分的偏移量(即, 写入完成。
- 如果 lpOverlappedNULL,则写入操作从当前文件位置开始,WriteFile 在操作完成之前不会返回,并且系统会在 WriteFile 返回之前更新文件指针。
- 如果 lpOverlapped 未 NULL,则写入操作从在 OVERLAPPED 结构中指定的偏移量开始,WriteFile 在写入操作完成之前不会返回。 系统更新 OVERLAPPED Internal 和 InternalHigh 字段以及文件指针,然后 WriteFile 返回。
管道
如果使用匿名管道并且读取句柄已关闭,则当 WriteFile 尝试使用管道的相应写入句柄进行写入时,该函数将返回 FALSE,GetLastError 返回 ERROR_BROKEN_PIPE。如果应用程序使用 WriteFile 函数写入管道时管道缓冲区已满,则写入操作可能不会立即完成。 当读取操作(使用 ReadFile 函数)使更多的系统缓冲区空间可用于管道时,写入操作将完成。
写入到缓冲区空间不足的非阻塞字节模式管道句柄时,
有关管道的详细信息,请参阅 管道。
事务处理操作
如果存在绑定到文件句柄的事务,则会处理文件写入。 有关详细信息,请参阅 关于事务 NTFS。例子
有关一些示例,请参阅 创建和使用临时文件,并 打开文件以读取或写入。
以下C++示例演示如何对齐未缓冲区文件写入的扇区。 Size 变量是想要写入文件的原始数据块的大小。 有关未缓冲文件 I/O 的其他规则,请参阅 文件缓冲。#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 |