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 函数打开的任何句柄,也可以是套接字或 accept 函数返回的套接字句柄。
[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 ,如果使用此参数,则必须指定开始写入文件或设备的字节偏移量。 此偏移量是通过设置 OVERLAPPED 结构的 Offset 和 OffsetHigh 成员指定的。 对于不支持字节偏移量的 hFile , 将忽略 Offset 和 OffsetHigh 。
若要写入文件末尾,请将 OVERLAPPED 结构的 Offset 和 OffsetHigh 成员指定为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 中指定FILE_FLAG_WRITE_THROUGH,以确保将整个多扇区写入磁盘,而不会造成潜在的缓存延迟。
如果直接写入具有已装载文件系统的卷,则必须先获取该卷的独占访问权限。 否则,可能会导致数据损坏或系统不稳定,因为应用程序的写入操作可能与来自文件系统的其他更改冲突,并使卷的内容处于不一致状态。 为防止这些问题,Windows Vista 及更高版本中进行了以下更改:
- 如果卷没有装载的文件系统,或者满足以下条件之一,则对卷句柄的写入将成功:
- 要写入的扇区是启动扇区。
- 要写入的扇区驻留在文件系统空间之外。
- 已使用 FSCTL_LOCK_VOLUME 或 FSCTL_DISMOUNT_VOLUME 显式锁定或卸载卷。
- 该卷没有实际的文件系统。 (换句话说,它具有 RAW 文件系统 mounted.)
- 如果满足以下条件之一,则磁盘句柄上的写入将成功:
- 要写入的扇区不在卷的范围内。
- 要写入的扇区位于已装载卷内,但已使用 FSCTL_LOCK_VOLUME 或 FSCTL_DISMOUNT_VOLUME 显式锁定或卸载卷。
- 要写入到的扇区位于没有除 RAW 以外的已装载文件系统的卷内。
如果使用 FILE_FLAG_OVERLAPPED 打开 hFile,则以下条件有效:
- lpOverlapped 参数必须指向有效且唯一的 OVERLAPPED 结构,否则函数可能会错误地报告写入操作已完成。
- lpNumberOfBytesWritten 参数应设置为 NULL。 若要获取写入的字节数,请使用 GetOverlappedResult 函数。 如果 hFile 参数与 I/O 完成端口相关联,则还可以通过调用 GetQueuedCompletionStatus 函数来获取写入的字节数。
技术 | 支持 |
---|---|
服务器消息块 (SMB) 3.0 协议 | 是 |
SMB 3.0 透明故障转移 (TFO) | 是 |
具有横向扩展文件共享的 SMB 3.0 (SO) | 是 |
群集共享卷文件系统 (CSV) | 是 |
弹性文件系统 (ReFS) | 是 |
同步和文件位置
如果使用 FILE_FLAG_OVERLAPPED 打开 hFile,则它是异步文件句柄;否则,它是同步的。 如前所述,每个使用 OVERLAPPED 结构的规则略有不同。- WriteFile 可能会在写入操作完成之前返回。 在此方案中, WriteFile 返回 FALSE , GetLastError 函数返回 ERROR_IO_PENDING,这允许调用进程在系统完成写入操作时继续。
- lpOverlapped 参数不能为 NULL,并且应考虑到以下事实:
- 尽管在 OVERLAPPED 结构中指定的事件由系统自动设置和重置,但在 OVERLAPPED 结构中指定的偏移量不会自动更新。
- WriteFile 在开始 I/O 操作时将事件重置为非对齐状态。
- 在 OVERLAPPED 结构中指定的事件在写入操作完成时设置为信号状态;在该时间之前,写入操作被视为挂起。
- 由于写入操作从 OVERLAPPED 结构中指定的偏移量开始,并且 WriteFile 可能在系统级写入操作完成之前返回, (写入挂起) ,因此,在事件发出信号之前,应用程序不应修改、释放或重复使用该结构的任何其他部分,直到事件发出信号 (, 写入) 完成。
- 如果 lpOverlapped 为 NULL,则写入操作从当前文件位置开始, 并且 WriteFile 在操作完成之前不会返回,并且系统会在 WriteFile 返回之前更新文件指针。
- 如果 lpOverlapped 不为 NULL,则写入操作在 OVERLAPPED 结构中指定的偏移量处开始, 并且 WriteFile 在写入操作完成之前不会返回。 在 WriteFile 返回之前,系统将更新 OVERLAPPED Internal 和 InternalHigh 字段以及文件指针。
管道
如果使用匿名管道且已关闭读取句柄,当 WriteFile 尝试使用管道的相应写入句柄进行写入时,函数返回 FALSE , GetLastError 返回 ERROR_BROKEN_PIPE。如果应用程序使用 WriteFile 函数写入管道时管道缓冲区已满,则写入操作可能不会立即完成。 当使用 ReadFile 函数 (读取操作) 为管道提供更多系统缓冲区空间时,将完成写入操作。
写入缓冲区空间不足的非阻塞的字节模式管道句柄时, WriteFile 返回 TRUE ,其中包含 *lpNumberOfBytesWritten<nNumberOfBytesToWrite。
有关管道的详细信息,请参阅 管道。
事务处理操作
如果存在绑定到句柄的事务,则会事务处理文件写入。 有关详细信息,请参阅 关于事务 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 应用] |
目标平台 | Windows |
标头 | fileapi.h (包括 Windows.h) |
Library | Kernel32.lib |
DLL | Kernel32.dll |
另请参阅
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈