如何在无缓冲模式下执行 CopyFile?
摘要
说明了如何将 COPY_FILE_NO_BUFFERING 标志与 CopyFileEx 和 CopyFile2 一起使用,以使用无缓冲句柄复制文件,以及为什么在句柄打开后无法使用进度回调来更改缓冲模式。
<p>一位客户正在使用 <code>CopyFile</code> 复制文件,但他们希望文件句柄以 <code>FILE_<wbr />FLAG_<wbr />NO_<wbr />BUFFERING</code> 方式打开。</p>
<p>我们之前看到过 <a title="如何进行 CopyFile,但在目标句柄关闭之前刷新文件缓冲区?" href="https://devblogs.microsoft.com/oldnewthing/20221007-00/?p=107261">可以使用进度回调来让 <code>CopyFileEx</code> 或 <code>CopyFile2</code> 刷新输出句柄</a>。也许我们可以使用进度回调来以无缓冲方式打开句柄?</p>
<p>不,这行不通,因为进度回调给你的是已经打开的句柄。你无法在事后更改它的缓冲标志。</p>
<p>但这没关系,因为 <code>CopyFileEx</code> 和 <code>CopyFile2</code> 也有一个 flags 参数,其中一个标志是 <code>COPY_<wbr />FILE_<wbr />NO_<wbr />BUFFERING</code>,这意味着句柄应该以 <code>FILE_<wbr />FLAG_<wbr />NO_<wbr />BUFFERING</code> 打开。</p>
<pre>BOOL success = CopyFileEx(
sourceFilePath, destinationFilePath,
nullptr, nullptr, nullptr,
COPY_FILE_NO_BUFFERING);
</pre>
<p>你也可以用 <code>CopyFile2</code> 做同样的事情,但标志位于 options 结构体中。</p>
<pre>COPYFILE2_EXTENDED_PARAMETERS parameters{};
parameters.dwSize = sizeof(parameters);
parameters.dwCopyFlags = COPY_FILE_NO_BUFFERING;
HRESULT hr = CopyFile2(sourceFilePath, destinationFilePath, &parameters);
</pre>
<p>本文《<a href="https://devblogs.microsoft.com/oldnewthing/20260810-00/?p=112600">如何以无缓冲模式执行 CopyFile?</a>》最早出现在 <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a> 上。</p>
查看缓存全文
缓存时间: 2026/08/12 08:26
# 如何以非缓冲模式执行 CopyFile? - The Old New Thing
来源:https://devblogs.microsoft.com/oldnewthing/20260810-00?p=112600
有一位客户正在使用 `CopyFile` 复制文件,但他们希望文件句柄以 `FILE\_FLAG\_NO\_BUFFERING` 方式打开。
我们在不久前看到,你可以使用 `CopyFileEx` 或 `CopyFile2` 的进度回调来刷新输出句柄(https://devblogs.microsoft.com/oldnewthing/20221007-00/?p=107261)。也许我们可以利用进度回调以非缓冲方式打开句柄?
不行,这行不通,因为进度回调提供给你的是已经打开的句柄。你无法在事后更改它的缓冲标志。
不过没关系,因为 `CopyFileEx` 和 `CopyFile2` 也有一个标志参数,其中有一个标志就是 `COPY\_FILE\_NO\_BUFFERING`,它表示句柄应以 `FILE\_FLAG\_NO\_BUFFERING` 方式打开。
``
BOOL success = CopyFileEx(
sourceFilePath, destinationFilePath,
nullptr, nullptr, nullptr,
COPY_FILE_NO_BUFFERING);
``
使用 `CopyFile2` 也可以达到同样的目的,但标志需要放在选项结构中。
``
COPYFILE2_EXTENDED_PARAMETERS parameters{};
parameters.dwSize = sizeof(parameters);
parameters.dwCopyFlags = COPY_FILE_NO_BUFFERING;
HRESULT hr = CopyFile2(sourceFilePath, destinationFilePath, ¶meters);
``
### 分类
### 主题
## 作者
Raymond Chen
Raymond 参与 Windows 的发展已有 30 多年。2003 年,他创办了一个名为 The Old New Thing 的网站,其受欢迎程度远远超出他最狂野的想象,这一发展至今仍让他心生畏惧。该网站还催生了一本书,书名巧合地也叫 The Old New Thing(Addison Wesley 2007 年出版)。他偶尔会出现在 Windows Dev Docs 的 Twitter 账号上,讲述一些不传达有用信息的故事。
相似文章
Go中的零拷贝: sendfile、splice 以及 io.Copy 的成本
本文解释了Go的io.Copy如何自动使用sendfile和splice进行TCP上的零拷贝文件传输,并展示了将文件包装成普通的io.Reader(例如用于日志记录)会悄然禁用此优化,导致性能显著下降。基准测试和strace输出说明了这种影响。
std::function 与 copyable_function 的互转换
对 C++26 中 std::function 和 std::copyable_function 之间互转换的技术分析,讨论了实现方法和性能权衡,并特别指出 libstdc++ 目前采用了一种较次优的方法。
我使用 FILE_FLAG_DELETE_ON_CLOSE 打开了一个文件,但现在我改变主意了
说明 FILE_FLAG_DELETE_ON_CLOSE 是不可逆的,但你可以通过使用 SetFileInformationByHandle 切换删除处置来实现条件删除。
为Windows 3.1改造WM_COPYDATA消息
本文解释如何利用共享地址空间,将针对32位Windows引入的WM_COPYDATA消息改造到16位Windows 3.1上,使得16位程序间的通信无需任何更改。
如何告知Windows我正在写入二进制文件?
本文解释了Windows在操作系统层面并没有内置二进制与文本模式的概念;这种区别是由运行时库(如C运行时)处理的。它澄清了Windows将所有文件视为字节,内容转换必须手动执行或通过库来完成。