如果文件正在更改(即正在下载的文件),Powershell 无法正确读取文件大小

Edu*_*Uta 3 powershell ntfs filesize

我正在编写一个 Powershell 脚本,旨在在一个或多个文件下载完成后关闭 Windows 计算机(笔记本电脑/PC)(为了举例说明,我们假设这里有一个大文件)。

简而言之,我们每 x 秒读取整个下载文件夹的大小,并比较之前和之后的延迟大小。如果最近一段时间没有变化,则说明下载要么完成,要么卡住,这两种情况都会导致关机。

给出以下脚本(尺寸获取器在某些时候可以是一个独立的函数,是的):

#Powershell5
#Major  Minor  Build  Revision
# -----  -----  -----  --------
# 5      1      19041  1320  

$downloadDir = "C:\Users\edi\Downloads"

while (1) 
{
    $s1 = Get-ChildItem -Path $downloadDir | Measure-Object -Property Length -Sum | Select-Object Sum
    write-host "S1:" $s1.sum

    # this 3 seconds time is just for testing purposes; in real case scenario this will most
    # likely be set to 60 or 120 seconds.
    Start-Sleep -s 3

    $s2 = Get-ChildItem -Path $downloadDir | Measure-Object -Property Length -Sum | Select-Object Sum
    write-host "S2:" $s2.sum

    if ($s1.sum -eq $s2.sum) 
    {
        write-host "Download complete, shutting down.."
        # loop exit is this, actual shutdown; commented out for testing purposes.
        #shutdown /s
    } 
}
Run Code Online (Sandbox Code Playgroud)

我面临的问题是文件大小读取不是“实时”完成的。换句话说,文件大小不会像您通常在资源管理器视图中看到的那样发生变化。我需要能够实时读取这些数字(更改文件大小)。

有趣的事实:当下载正在进行且脚本运行时,如果手动转到下载文件夹并按 F5/刷新...,数字会发生变化(大小读数是准确的)。

旁注:我的研究让我看到了这篇文章,它可能会提出根本原因,但我不能 100% 确定它:https ://devblogs.microsoft.com/oldnewthing/20111226-00/?p=8813

感谢对此的任何想法。提前致谢!

mkl*_*nt0 5

我建议采取不同的策略:

  • 为每个下载过程设置总体超时时间,例如curl.exe--max-time选项。

  • 不幸的是,PowerShell 自己的Invoke-WebRequest似乎Invoke-RestMethod只有连接超时 ( -TimeoutSec),而不是整体连接的超时。

这样您就可以跟踪下载进程,并在所有下载进程终止后触发重新启动(无论是由于完成还是超时)。


至于你的方法

  • 正如您所观察到的,您可以查询的磁盘上文件大小在写入文件时Get-ChildItem不会连续更新,尽管最终会更新,但直到文件关闭完全写入)后,这种情况可能不会发生。 。

  • 但是,您可以按需更新文件大小信息,即通过方法System.IO.FileSystemInfo.Refresh(),这相当于通过文件资源管理器执行的手动刷新。

    • 但请注意,由于写入的内部缓冲,这仍然不是实时大小信息。
# Perform this before every Measure-Object call.
# It refreshes the size information of all files in the specified dir.
(Get-ChildItem -File -LiteralPath $downloadDir).Refresh()
Run Code Online (Sandbox Code Playgroud)

顺便说一句:正如 Santiago 指出的那样,这种方法从根本上不适用于预分配的下载实用程序/API具有下载完整大小的输出文件,而某些 BitTorrent 客户端显然提供了这一功能。

至于缩小已完成的下载与假设被卡住的下载的范围:

Invoke-WebRequest/Invoke-RestMethod在下载过程中独占锁定其输出文件,因此您可以尝试读取哪些文件无法读取,从中您可以推断哪些下载(如果有)仍在进行中:

# Note: In PowerShell (Core) 7+, use -AsByteStream instead of -Encoding Byte
Get-ChildItem -File -LiteralPath $downloadDir | 
  Get-Content -Encoding Byte -First 1 -ErrorVariable errs -ErrorAction SilentlyContinue |
    Out-Null

if ($errs) { Write-Warning "Incomplete downloads:`n$($errs.TargetObject)" }
Run Code Online (Sandbox Code Playgroud)