我可以优化此PowerShell解析器吗

时间:2019-02-21 11:03:02

标签: powershell

我编写了一个PowerShell脚本来读取分隔的文件并逐行遍历它们。 该脚本将属性值保存到变量中,并在遇到字符串结尾时将这些值写入文件中。

假设没有安装.Net框架,是否有办法优化此脚本以提高速度?

class FastLapsSet(ModelViewSet):
queryset = Fastest_laps.objects.all()
serializer_class = ListSerializer

class DriverSet(ModelViewSet):
queryset = Driver.objects.all()
serializer_class = DetailSerializer

2 个答案:

答案 0 :(得分:0)

Get-Content .\a.txt运行缓慢,请用速度更快的[system.io.file]::ReadAllLines('c:\full\path\to\file\a.txt')替换。

摆脱整个第一个循环,根本不回显有多少工作。如果必须这样做,则将循环推入堆栈,并使用$jobCount = ($LinesLoadedOnce -match '^end$').Count并使用-match而不是foreach来进行循环/过滤。

与其每行文本文件多次调用Clear-Variable并导致多次启动cmdlet的开销,不如调用一次并将其传递给要清除的名称数组,例如Clear-Variable -Name "insert_job", "job_type", "command", ..

代替使用>>storage.txt每行打开和关闭txt文件一次,而是将输出收集到数组中,然后使用set-content将其写入文件一次。

$results = foreach ($line in [system.io.file]::ReadAllLines('c:\full\path\to\file\a.txt'))
{
    #code here

    "'$insert_job','$job_type','$command', .."

}

$results | Set-Content -Path storage.txt

其余的内容更多地取决于文件的格式,文件的大小,如果要跳过的行,但可能会变成类似以下内容:

$headers = @(
    'insert_job'
    'job_type'
    'command'
    'machine'
    'owner'
    'permission'
    'date_conditions'
    'days_of_week'
    'start_times'
    'description'
    'std_out_file'
    'std_err_file'
    'alarm_if_fail'
    'end'
    'box_name'
    'condition'
    'run_window'
    'n_retrys'
    'term_run_time'
    'box_terminator'
    'job_terminator'
    'min_run_alarm'
    'max_run_alarm'
    'profile'
)

$headerRegex = "^($($headers -join '|'))\s*:\s*(.*?)\s*$"

$data = [ordered]@{}
foreach($h in $headers) { $data[$h] = $null }

$results = foreach ($line in [system.io.file]::ReadAllLines('c:\full\path\to\file\a.txt')) {

    if ($line -match $headerRegex) {
        $data[$matches[1]] = $matches[2]
    }
    elseif ($line -eq 'end') {
        [PSCustomObject]$data
        $data = [ordered]@{}
        foreach($h in $headers) { $data[$h] = $null }
    }
}

$results | Export-Csv storage.txt -NoTypeInformation

这将更多的工作投入正则表达式引擎,减少字符串处理和字符串插值,使用更少的变量和更少的cmdlet,避免所有切换和中断跳动,并且运行速度更快。

我没有测试过,因为我不知道您文件的内容。

答案 1 :(得分:0)

注释和TessellatingHeckler's answer中都有很好的指针,但是让我尝试将所有内容与速度改进一起使用-请参见代码中的注释。

rm storage.txt
$job_counter = 0
$att_counter = 0

# Read all lines into memory up front, using the .NET framework directly
# which is much faster than using Get-Content.    
$allLines = [IO.File]::ReadAllLines("$PWD/a.txt")

# Count the lines that contain 'end' exactly to determine
# the number of jobs.
$job_counter = ($allLines -eq 'end').Count

"File has $job_counter jobs"

$job_counter = 0

# Initialize the hashtable whose entries will contain the values
# (rather than individual variables).
$values = [ordered] @{}

# Use a `switch` statement to process the lines, which is generally
# faster than a `foreach` loop.
switch ($allLines) {
  'end' {  # Use string equality (not regex matching), which is faster.
    $job_counter++
    "encountered job number $job_counter, it has $att_counter attributes"
    # Write the values to 
    "'$($values.insert_job)','$($values.job_type)','$($values.command)','$($values.machine)','$($values.owner)','$($values.permission)','$($values.date_conditions)','$($values.days_of_week)','$($values.start_times)','$($values.description)','$($values.std_out_file)','$($values.std_err_file)','$($values.alarm_if_fail)','$($values.end)','$($values.box_name)','$($values.condition)','$($values.run_window)','$($values.n_retrys)','$($values.term_run_time)','$($values.box_terminator)','$($values.job_terminator)','$($values.min_run_alarm)','$($values.max_run_alarm)','$($values.profile)'" >>storage.txt
    # Clear the values from the hashtable.
    $values.Clear()
  }
  default { 
    # Split the line at hand into field name and value...
    $fieldName, $value = $_ -split ':', 2, 'SimpleMatch'
    # ... and add an entry for the pair to the hashtable.
    $values.$fieldName = $value.trim()
    $att_counter++
  }
}

注意:上面的解决方案未验证输入文件中的字段名称;为此,需要额外的工作。