Powershell foreach 读写速度慢

Powershell foreach read write slow

提问人:CaptainCrunch 提问时间:10/28/2022 更新时间:10/28/2022 访问量:80

问:

我有几百个文件,每个文件大约 1.5 MB。我需要针对以下循环运行文件,但它非常慢。每个文件大约需要 5 分钟才能循环完成。有没有更快的方法?

function Convert-File($inputFile,$outputFile,$dataDate)
{
if ([string]::IsNullOrEmpty($dataDate)) 
{
$dataDate = $inputFile.split('.') | select -last 1
}
Write-Host "File data date is $dataDate"
#Get-Content $inputFile | Select-String -pattern $dataDate | Out-File $outputFile
$header=""
$headerOut=$false
if (Test-Path $outputFile) 
{
  Remove-Item $outputFile
}
foreach($line in [System.IO.File]::ReadLines($inputFile))
{
    if ($line.StartsWith("!"))
    {
        $header=$line
        continue
    }
    if ($line.Contains($dataDate))
    {
        if (!$headerOut) 
        {
        $headerOut=$true
        #Write-Host $header
        Set-Content -Path $outputFile -Value $header.substring(1).Replace('|',',') -Force
        }
        if ([string]::IsNullOrEmpty($line)) { continue }
        #Write-Host $line
        Add-Content $outputFile $line.Replace('|',',') -force
    }
}
}

代码有效,但我希望代码执行得更快。有什么建议吗?

PowerShell 性能 IO

评论

0赞 Santiago Squarzon 10/28/2022
你的瓶颈在这一行,你应该改用一个。您能否简要说明您的代码正在做什么,以便任何阅读您问题的人都知道。Add-Content $outputFile $line.Replace('|',',') -forceStreamWriter

答:

1赞 Santiago Squarzon 10/28/2022 #1

Add-Content 是代码中的瓶颈,在每次循环迭代中打开和关闭 FileStream 的成本非常高。此操作应仅执行一次

另外,值得注意的是 [string]::IsNullOrEmpty( ) 应该是循环的第一个条件,并且很可能您想使用 [string]::IsNullOrWhiteSpace( ) 来代替,尽管我会留给您决定。

这是你的最终循环应该如何使用 StreamWriter 循环:

try {
    foreach($line in [System.IO.File]::ReadLines($inputFile)) {
        if ([string]::IsNullOrEmpty($line)) {
            continue
        }
        if ($line.StartsWith('!')) {
            $header = $line
            continue
        }
        if ($line.Contains($dataDate)) {
            if (-not $headerOut) {
                $headerOut = $true

                $fs     = (New-Item $outputFile -Force).OpenWrite()
                $writer = [System.IO.StreamWriter] $fs
                $writer.WriteLine($header.SubString(1).Replace('|', ','))
            }

            $writer.WriteLine($line.Replace('|', ','))
        }
    }
}
finally {
    $writer, $fs | ForEach-Object Dispose
}

评论

1赞 CaptainCrunch 10/28/2022
谢谢。从最初阅读您的建议开始,我就能够弄清楚。谢谢你发布这个。我是 Powershell 的新手,所以这给了我一个更好的视角。