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

noj0wjuj  于 2023-01-13  发布在  Shell
关注(0)|答案(2)|浏览(170)

我正在编写一个Powershell脚本,目的是在完成一个或多个文件的下载后关闭Windows机器(笔记本电脑/PC)(为了示例起见,让我们假设这里有一个大文件)。
简而言之,我们每隔x秒阅读一次整个下载文件夹的大小,然后比较延迟前后的大小。如果最近的时间没有变化,这意味着下载完成或卡住,两种情况都会导致关机。
给定以下脚本(size getter在某些时候可以是一个独立函数,是的):

#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
    } 
}

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

**有趣的事实:**当下载正在进行且脚本正在运行时,如果手动转到downloads文件夹并按F5 / Refresh...数字会发生变化(大小阅读准确)。
**旁注:**我的研究让我看到了这篇文章,它可能提供了根本原因,但我不能100%确定:https://devblogs.microsoft.com/oldnewthing/20111226-00/?p=8813

感谢任何关于这方面的想法。提前感谢!

9nvpjoqh

9nvpjoqh1#

我建议采取不同的策略:

  • 为每个下载进程设置一个总超时,例如curl.exe--max-time选项。
  • 不幸的是,PowerShell自己的Invoke-WebRequestInvoke-RestMethod似乎只有一个 * 连接 * 超时(-TimeoutSec),而不是整个连接的超时。

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

  • 您可以通过Get-ChildItem查询的磁盘上的文件大小在写入文件时不会 * 持续 * 更新,正如您所观察到的,虽然它是*最终 * 更新的,但这种情况可能不会发生,直到文件被 * 关闭 ,即完全写入
  • 您可以尝试基于Santiago Squarzon's helpful answer的限制写入。
  • 但是,您可以 * 按需 * 更新文件大小信息,即通过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()

顺便说一句:正如圣地亚哥所指出的,这种方法根本不适用于下载实用程序/API,这些实用程序/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)" }
gab6jxml

gab6jxml2#

这个答案是为了证明,* 即使不可靠 *,文件大小可以实时监控。在这种情况下,[System.IO.StreamWriter]在一个单独的作业中将数据附加到文件,而主线程监控当前文件夹大小。
我还执行了相同的测试while downloading a "test file",它对我来说工作正常,文件夹的总大小正在正确更新。
你所观察到的可能原因和纯粹基于假设:

  • 正在下载的文件有预分配的空间-我不认为这是可能的,因为,正如你解释的,通过查看资源管理器,你可以看到文件大小增加。
  • size beforesize after 计算之间没有足够的时间-这可能是由于缓冲,mklement0已经详细解释了这一点。增加睡眠时间可能会解决这个问题。另外,调用.Refresh() method,正如他在有用的回答中解释的那样,可能会有所帮助。

我个人认为这不是解决这个问题的正确方法,进程监控会是一个更好的方法(假设这是可能的--mklement 0也解释过,我完全同意他的观点)。

function Get-FolderSize {
    param($Path = $PWD)

    ($Path | Get-ChildItem -File | Measure-Object -Property Length -Sum).Sum
}

$startingSize = Get-FolderSize

$job = Start-Job {
    try {
        $chunk   = 'a' * 10kb
        $tmpFile = Join-Path $PWD -ChildPath "testfile.dump"
        $writer  = [System.IO.StreamWriter] $tmpFile
        $writer.AutoFlush = $true

        foreach($i in 0..200kb) {
            $writer.WriteLine($chunk)
        }
    }
    finally {
        $writer.Dispose()
        $tmpFile | Remove-Item
    }
}

try {
    do {
        $sizeBefore = Get-FolderSize
        $waitId     = [Threading.WaitHandle]::WaitAny($job.Finished, 5000)
        $sizeAfter  = Get-FolderSize

        '[StartSize {0, -5} | SizeBefore {1, -10} | SizeAfter {2, -10}]' -f @(
            $startingSize
            $sizeBefore
            $sizeAfter
        )
    }
    while ($waitId -eq [Threading.WaitHandle]::WaitTimeout)
}
finally {
    $job | Stop-Job -PassThru | Remove-Job
}

我的结果:

[StartSize 11270 | SizeBefore 11270      | SizeAfter 400391534 ]
[StartSize 11270 | SizeBefore 400391534  | SizeAfter 847762094 ]
[StartSize 11270 | SizeBefore 847762094  | SizeAfter 1349824934]
[StartSize 11270 | SizeBefore 1349824934 | SizeAfter 1744551614]
[StartSize 11270 | SizeBefore 1744551614 | SizeAfter 11270     ]

相关问题