重写Write-Host的奇怪副作用

时间:2016-06-18 16:00:14

标签: powershell

我看到一些我似乎无法解释的奇怪行为。

流式传输文本文件的代码工作正常。

$journalPath = "$(Split-Path $($script:myInvocation.myCommand.path) -parent)\Journals"

$journals = Get-ChildItem $journalPath -filter "journal.*.txt"

Write-Host "Streaming"
foreach ($journal in $journals) {
    $reader = [System.IO.File]::OpenText("$journalPath\$journal")
    do {
        $line = ($reader.ReadLine()).Trim()
        if (-not ($line.StartsWith("'"))) {
            Write-Host $line
        }
    } until ($line -eq $null)

    $reader.Close()
}

但是,如果我退出Write-Host行,我会得到

You cannot call a method on a null-valued expression.

第9行,$reader.ReadLine()行。为什么简单的Write-Line会产生这种影响呢?

1 个答案:

答案 0 :(得分:0)

与(所谓的 pretest While () {…}循环不同,所有(所谓的 posttest Do {…} While ()以及Do {…} Until () }循环将始终执行其代码块至少一次,因为条件发生在循环结束。

下一个示例显示逐行循环文件内容的基本方案,包括 inept ,显示读取行是否可以在当前迭代/重复中计算为空值表达式。请注意,您无需拨打.NET File Class [System.IO.File]

$journalPath = "$(Split-Path $($script:myInvocation.myCommand.Path) -parent)\Journals"
$journals = Get-ChildItem $journalPath -filter "journal*.txt"
foreach ($journal in $journals) {
    Write-Host "`r`n" (" " * 10) "testing " $journal.Name

    'DO {} WHILE ( $line -ne $null )'
    $reader = [System.IO.File]::OpenText("$journalPath\$journal")
    Do {
         $line = $reader.ReadLine()
         Write-Host (" " * 14) ($line -eq $null) $reader.EndOfStream
       } While ( $line -ne $null )
    $reader.Close()

    'DO {} UNTIL ( $line -eq $null )'
    $reader = [System.IO.File]::OpenText("$journalPath\$journal")
    Do { 
         $line = $reader.ReadLine()
         Write-Host (" " * 14) ($line -eq $null) $reader.EndOfStream
       } Until ( $line -eq $Null )
    $reader.Close()

    'DO {} WHILE ( -not $reader.EndOfStream )'
    $reader = [System.IO.File]::OpenText("$journalPath\$journal")
    Do {
         $line = $reader.ReadLine()
         Write-Host (" " * 14) ($line -eq $null) $reader.EndOfStream
       } While ( -not $reader.EndOfStream )
    $reader.Close()

    'DO {} UNTIL ( $reader.EndOfStream )'
    $reader = [System.IO.File]::OpenText("$journalPath\$journal")
    Do { 
         $line = $reader.ReadLine()
         Write-Host (" " * 14) ($line -eq $null) $reader.EndOfStream
       } Until ( $reader.EndOfStream )
    $reader.Close()

    'WHILE ( -not $reader.EndOfStream ) {}' 
    $reader = [System.IO.File]::OpenText("$journalPath\$journal")
    While ( -not $reader.EndOfStream) {
         $line = $reader.ReadLine()
         Write-Host (" " * 14) ($line -eq $null) $reader.EndOfStream
    }
    $reader.Close()

    'FOREACH-OBJECT {}'
    $journal | Get-Content -Encoding UTF8 | ForEach-Object {
        Write-Host (" " * 14) ($_ -eq $null)
    }
}

任何人都可以看到唯一可接受的方案是那些包含'FOREACH-OBJECT {}''WHILE ( -not $reader.EndOfStream ) {}'子标题的方案:

PS D:\PShell> D:\PShell\SO\37898929.ps1

            testing  journal37898929-none_lines.txt
DO {} WHILE ( $line -ne $null )
               True True
DO {} UNTIL ( $line -eq $null )
               True True
DO {} WHILE ( -not $reader.EndOfStream )
               True True
DO {} UNTIL ( $reader.EndOfStream )
               True True
WHILE ( -not $reader.EndOfStream ) {}
FOREACH-OBJECT {}

            testing  journal37898929-some_lines.txt
DO {} WHILE ( $line -ne $null )
               False False
               False False
               False True
               True True
DO {} UNTIL ( $line -eq $null )
               False False
               False False
               False True
               True True
DO {} WHILE ( -not $reader.EndOfStream )
               False False
               False False
               False True
DO {} UNTIL ( $reader.EndOfStream )
               False False
               False False
               False True
WHILE ( -not $reader.EndOfStream ) {}
               False False
               False False
               False True
FOREACH-OBJECT {}
               False
               False
               False

PS D:\PShell> 

进一步阅读:PowerShell loops: For, Foreach, While, Do-Until, Continue, Break