【问题标题】:Is it safe to block in callback of CopyFileEx?阻止 CopyFileEx 的回调是否安全?
【发布时间】:2018-08-24 02:23:45
【问题描述】:

Windows API 函数 CopyFileEx 允许指定一个回调函数,当文件的一部分被复制到例如向用户提供有关进度的反馈。

这在我的程序中运行良好,但我现在有一个额外的要求:我需要暂时暂停复制过程,以便在一段时间内(可能长达几个小时)保持系统负载低,然后恢复它。这可能随时发生,并且通常有一个大文件(几个 100 GB)只被部分复制,因此中止进程并重新启动它不是一个好的选择,因为这意味着可能 99% 的文件已经被复制了,需要重新复制。

这样做的一个选择是简单地让执行复制的线程在调用回调时休眠,例如

function ProgressCallback(
  _TotalFileSize, _TotalBytesTransferred, _StreamSize,
  _StreamBytesTransferred: LARGE_INTEGER;
  _StreamNumber, _CallbackReason: LongWord;
  _SourceFile, _DestinationFile: THandle; _Data: Pointer): LongWord;
  far; stdcall;
begin
  // [...]
  while gblPauseFlag do
    sleep(100);
end;

(这当然是简化的代码。原始代码太复杂,无法在此处发布。)gblPauseFlag 将由应用程序中检查暂停条件的不同线程设置和重置。

我知道有更好的方法来暂停线程(事件、关键部分或其他),但这里的问题只是:在回调函数中暂停复制线程是否安全?还是会阻止某些 Windows 功能或资源?

从示例代码中可以看出,这是一个 Delphi 程序,但我认为这并不重要,所以我没有将问题标记为 [delphi]。

编辑:我可以传递标志 COPY_FILE_RESTARTABLE,但是:

在复制失败时在目标文件中跟踪复制的进度。 失败的副本可以在稍后重新启动,方法是指定相同的 lpExistingFileName 和 lpNewFileName 的值与调用中使用的值相同 那失败了。 这会显着减慢复制操作,因为 在复制操作期间,新文件可能会被多次刷新。

来源:CopyFileEx documentation

所以我宁愿尽量避免这种情况。

【问题讨论】:

  • 这是安全的。在这种情况下,您只暂停您的线程。
  • WTF 我的问题被否决了吗?请至少留下一条评论来解释该投票!
  • 您可能应该解释一下,为什么显而易见的解决方案(从您的 CopyProgresssRoutine 返回 PROGRESS_STOP)对您不起作用。
  • @IInspectable 这需要COPY_FILE_RESTARTABLE 标志。来自参考:“这会显着减慢复制操作”
  • @RbMm 这得到了this question的确认。

标签: winapi file-copying


【解决方案1】:

理想情况下,当您要复制如此大的文件时,您应该使用robocopy 之类的实用程序来处理大文件。如果您仍然喜欢编写自己的实用程序,请使其可以重新启动中止的副本。您可以使用文件流将有关副本进度的元数据存储在目标文件中。

【讨论】:

  • Robocopy 在这里不是一个选项。我需要使用我自己的程序,因为它与该计算机上的其他程序通信以知道要复制什么(更重要的是:要复制什么)以及何时暂停。
猜你喜欢
  • 2011-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-19
  • 1970-01-01
  • 2015-05-24
  • 2011-11-06
  • 2019-09-20
相关资源
最近更新 更多