使用超时参数的Copy-Item

3
我正在从一台硬盘中恢复文件,其中有一些文件无法读取。我无法更改硬件级别的超时/ERC,并且当我有数十万个文件,其中可能有数万个无法读取时,工作非常困难。
数据问题是控制器故障的结果。购买匹配的驱动器(完全一致),我已经能够访问驱动器,并可以无问题地复制大量数据。然而,在整个驱动器中散布着无法读取的文件,当访问它们时,会导致SATA总线挂起。我使用了各种可恢复文件复制应用程序,如robocopy、RichCopy和其他十几个应用程序,但它们都存在同样的问题。它们具有基于驱动器实际报告错误的重试计数。问题在于驱动器需要花费非常长的时间来报告错误,这意味着单个文件可能需要长达一小时才能正式失败。我知道每个文件应该有多快,所以我想构建一个Powershell CMDLET或类似的程序,允许我传递源文件名和目标文件名,并尝试复制该文件。如果5秒钟后未复制文件(或者已经复制了-这可以是一个愚蠢的过程),我希望它停止。我将编写一个脚本,单独启动每个复制过程,在等待它之前完成该进程,但到目前为止,我无法找到一个很好的方法来设置进程的时间限制。
如果您有任何建议,将不胜感激!
编辑:我将使用一个新线程生成一个 Copy-Item ,带有新PID,然后倒数,然后杀死该PID,这样也可以。我只是PowerShell的新手,并且看到了许多矛盾的方法来施加计时器,所以我迷失在最佳实践的方法上。
编辑2:请注意,像robocopy这样的应用程序在遇到磁盘的坏区域时会完全挂起。这些不是简单的挂起,而是总线挂起,Windows会尝试保存这些挂起,以便不会丢失数据。在这些情况下,任务管理器无法终止该进程,但是Process Explorer可以。我不确定方法论的区别是什么,但无论如何,这似乎与问题相关。

@lloyd 这将在超时后再次尝试,时间间隔为10秒。 - Ansgar Wiechers
是的,请用您需要的值替换它,并将其放置在 try catch 块 中(如果需要)。/mt 将为您提供多个线程。 - lloyd
好的,我会提出一个解决方案,但通常你应该尝试自己解决并展示你的代码。 - lloyd
我已经尝试了几种编码方式,但在每种情况下,我都无法找到终止子进程的方法。有人向我指出PowerShell是一个选项,但这不是我过去使用过的脚本语言。似乎Try/Catch在传统上非常普遍,因为它似乎期望异常才能捕获。没有异常,所以也就没有什么可以捕获的了。我想我可以将复制进程的实例化包装在一个块中,在几秒钟后故意引发异常,然后最终杀死我在代码中生成的PID? - Bruce the Hoon
我还没有看到任何代码,请使用PowerShell或其他语言更新您的问题,我可以更具体地回答。 - lloyd
显示剩余2条评论
1个回答

8

我认为在PowerShell中处理这种事情的规范方法是使用后台作业

$timeout = 300 # seconds

$job = Start-Job -ScriptBlock { Copy-Item ... }
Wait-Job -Job $job -Timeout $timeout
Stop-Job -Job $job
Receive-Job -Job $job
Remove-Job -Job $job

将脚本块中的Copy-Item替换为您想要运行的任何命令。但请注意,您想要在脚本块内使用的所有变量都必须在脚本块内定义、通过-ArgumentList参数传递或加上using:作用域限定符。

Wait-Job相比,另一种选择是等待作业完成或超时的循环:

$timeout = (Get-Date).AddMinutes(5)
do {
  Start-Sleep -Milliseconds 100
} while ($job.State -eq 'Running' -and (Get-Date) -lt $timeout)

非常感谢您提供的指针!正如我所怀疑的那样,由于SATA悬挂时出现问题,进程在结束时并不被终止,只能通过断开驱动器来释放。我用一个已知工作驱动器的副本进行了测试,结果与预期完全一致。如果进程没有被终止,我的下一步将是向微控制器发送一个断电命令,以中断文件之间的过程。这段代码确实适当地处理了时间问题,我非常感激!谢谢!编辑:还要感谢您的编辑帮助! - Bruce the Hoon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接