我可以使这个剧本更快吗?

我为实习编写了一个简单的脚本,通过提供的目录浏览并删除任何超过指定天数的文件。 我已经花了我所有的空闲时间,试图收紧。 这是迄今为止我所得到的:

function delOld($dir, $numDays){ $timespan = new-timespan -days $numDays $curTime = get-date get-childItem $dir -Recurse -file | where-object {(($curTime)-($_.LastWriteTime)) -gt $timespan} | remove-Item -whatif } 

这是一个函数调用的例子:

 delOld -dir "C:\Users\me\Desktop\psproject" -numDays 5 

对于阅读的难点,我发现将这些操作压缩成一行比将它们重新分配给每个迭代的易读variables更有效率。 为了testing目的,删除项目目前已被删除。 我知道,在这一点上,我可能无法加速太多,但是,我正在运行一个TB文件,所以每个操作都很重要。

预先感谢您提供的任何build议!

保持在PowerShell和.NET方法的领域,下面是如何加快你的功能:

  • 先计算一次截断时间戳。

  • 使用[IO.DirectoryInfo]类型的EnumerateFiles()方法(PSv3 + / .NET4 +)与foreach 语句结合使用。 帽子的提示wOxxOm 。

    • EnumerateFiles()枚举一个文件,保持内存使用不变,类似于Get-ChildItem ,但比Get-ChildItem快。

      • 注意事项

        • EnumerateFiles() 总是包含隐藏的文件,而Get-ChildItem在默认情况下将它们排除在外,只有在指定-Force时才包含它们。
        • 如果由于缺少权限而有可能遇到无法访问的目录,请将整个 foreach语句放在try / catch块中,以确保处理所有可访问的文件。

        • 枚举顺序可以不同于Get-ChildItem

    • PowerShell的foreach 语句ForEach-Object cmdlet快得多,也比PSv4 + .ForEach .ForEach() 集合运算符更快。

  • 直接在循环体内的每个[System.IO.FileInfo]实例上调用.Delete()方法。

注意:为简洁起见,在下面的函数中没有错误检查,比如$numDays是否有一个允许的值,以及$dir是否指向一个已经存在的目录(如果它是一个基于自定义PS驱动器的路径,先用Convert-Path解决它)。

 function delOld($dir, $numDays) { $dtCutoff = [datetime]::now - [timespan]::FromDays($numDays) # Make sure that the .NET framework's current dir. is the same as PS's: [System.IO.Directory]::SetCurrentDirectory($PWD.ProviderPath) # Enumerate all files recursively. # Replace $file.FullName with $file.Delete() to perform actual deletion. foreach ($file in ([IO.DirectoryInfo] $dir).EnumerateFiles('*', 'AllDirectories')) { if ($file.LastWriteTime -lt $dtCutOff) { $file.FullName } } } 

注意:上面只是输出要删除的文件的路径; 用$file.Delete()替换$file.FullName来执行实际的删除操作。

许多PowerShell cmdlet比它们的.NET相当慢。 例如,您可以调用[System.IO.File]::Delete($_.FullName)来查看是否存在性能差异。 Get-ChildItem => [System.IO.Directory]::GetFiles(...)

要做到这一点,我会写一个小脚本,创建两个临时文件夹,每个文件夹里有100,000个空的测试文件。 然后调用封装在[System.Diagnostics.StopWatch]每个版本的函数。

一些示例代码:

 $stopwatch = New-Object 'System.Diagnostics.StopWatch' $stopwatch.Start() Remove-OldItems1 ... $stopwatch.Stop() Write-Host $stopwatch.ElapsedMilliseconds $stopwatch.Reset() $stopwatch.Start() Remove-OldItems2 ... $stopwatch.Stop() Write-Host $stopwatch.ElapsedMilliseconds 

PowerShell的更多布朗利点:在Powershell窗口中运行Get-Verb ,您可以看到已批准的动词列表。 建议PowerShell中的函数名为Verb-Noun ,所以像Remove-OldItems这样的东西可以适合账单。

这将删除并行处理中的所有内容。

 workflow delOld([string]$dir, [int]$numDays){ $timespan = new-timespan -days $numDays $curTime = get-date $Files = get-childItem $dir -Recurse -file | where-object {(($curTime)-($_.LastWriteTime)) -gt $timespan} foreach -parallel ($file in $files){ Remove-Item $File } } delOld -dir "C:\Users\AndrewD\Downloads" -numDays 8 

现在,如果它的很多文件夹试试这个