2012-12-14 44 views
0

嘗試實現一個自定義的尾狀函數,在檢查了幾個例子之後,我已經到了下面的代碼,這很好地工作(不加載整個文件來讀取X結束行,適用於網絡路徑...)如何使用流讀取器獲取X行

我現在的問題是我不知道如何移動流指針說10行之前它的當前位置?

作爲一種解決方法,我將指針移動到當前位置前的1024個字節,但我不知道這實際上涉及多少行。

$sr=New-Object System.IO.StreamReader($fs) 
$lastPosition=$sr.BaseStream.Length # final position of the file 
$currentPosition=$lastPosition - 1024 

任何人都可以指點我正確的方向嗎?

下面是完整的代碼:

function tail{ 
    [cmdletBinding()] 
    Param(
     [Parameter(Position=0, Mandatory=$true)] 
     [ValidateNotNullOrEmpty()] 
     [System.String] 
     $filename, # path 
     [int]$n=10, # number of lines to output 
     [switch]$continous, # continue to monitor for changes ? 
     [switch]$hilight # hilight lines containing keywords ? 
    ) 

    # Initialising stuff 
    [email protected]("erreur","error","fatal","critic") 
    [email protected]("attention","warning","notice") 
    $errorColor="red" 
    $warningColor="darkyellow" 

    if ((test-Path $filename) -eq $false){ 
     write-Error "Cant read this file !" 
     exit 
    } 

    function tailFile($ptr){ 
     # return each line from the pointer position to the end of file 
     $sr.BaseStream.Seek($ptr,"Begin") 
     $line = $sr.ReadLine() 
     while ($line -ne $null){ 
      $e=$w=$false 

      if($hilight){ 
       $hilightError | %{ $e = $e -or ($line -match $_) } # find error keywords ? 
       if($e) {wh $line -ForegroundColor $errorColor } 
       else{ 
        $hilightWarning | %{ $w = $w -or ($line -match $_) } # find warning keywords ? 
        if($w){ wh $line -ForegroundColor $warningColor } 
        else{ wh $line} 
       } 
      } 
      else{ #no hilight 
       wh $line 
      } 
      $line = $sr.ReadLine() 
     } 
    } 

    # Main 
    $fs=New-Object System.IO.FileStream ($filename,"OpenOrCreate", "Read", "ReadWrite",8,"None") # use ReadWrite sharing permission to not lock the file 
    $sr=New-Object System.IO.StreamReader($fs) 

    $lastPosition=$sr.BaseStream.Length # final position of the file 
    $currentPosition=$lastPosition - 1024 # take some more bytes (to get the last lines) 

    tailfile $currentPosition 

    if($continous){ 
     while(1){ 
      start-Sleep -s 1 
      # have the file changed ? 
      if ($sr.BaseStream.Length -eq $lastPosition){ 
       write-verbose "no change..." 
       continue 
      } 
      else { 
       tailfile $lastPosition 
       $lastPosition = $sr.BaseStream.Position 
      write-Verbose "new position $lastPosition" 
      } 
     } 
    } 
    $sr.close() 
} 
+0

我認爲你可以從這個答案爲C#採取提示:http://stackoverflow.com/a/4619770/520612 –

+0

@Christian謝謝你,我已經有更多的工作要做:) –

+0

你知道在V3中'get-content'有一個'-tail'參數嗎? –

回答

0

感謝Christian和Keith的提示。 最後我決定在streamreader中後退,直到它返回足夠的readline()。 我讓指定代碼頁的可能性,似乎與Unicode一致。 這裏是代碼,如果有人有興趣

function tail{ 
    [cmdletBinding()] 
    Param(
     [Parameter(Position=0, Mandatory=$true)] 
     [ValidateNotNullOrEmpty()] 
     [System.String] 
     $filename, # path 
     [int]$n=10, # number of lines to output, 
     [Alias("cp")] 
     $codepage=65001,#utf8 
     [Alias("f")] 
     [switch]$continous, # continue to monitor for changes ? 
     [switch]$hilight # hilight lines containing keywords ? 
    ) 
    # Initialising stuff 
    [email protected]("erreur","error","fatal","critic") 
    [email protected]("attention","warning","notice") 
    $errorColor="red" 
    $warningColor="yellow" 
    [System.Text.Encoding]$enc = [System.Text.Encoding]::GetEncoding($codepage) 

    function render($render){ 
     $e=$w=$false 
     if($hilight){ 
      foreach ($line in $render){ 
       $hilightError | %{ $e = $e -or ($line -match $_) } # find error keywords ? 
       if($e) {wh $line -ForegroundColor $errorColor } 
       else{ 
        $hilightWarning | %{ $w = $w -or ($line -match $_) } # find warning keywords ? 
        if($w){ wh $line -ForegroundColor $warningColor } 
        else{ wh $line} 
       } 
       $e=$w=$false 
      } 
     } 
     else{ #no hilight 
      wh $render 
     } 
    } 


    function TailFileBeforeEnd{ 
    #try to find $n lines before eof 

     $buffer=1024 
     $ptr=$lastPosition #start at the end of the file 
     $found=0 

     while($ptr -gt 0 -and $found -lt $n){ 
      $ptr-=$buffer 
      if ($ptr -le 0){$ptr=0} 
      $sr.BaseStream.Seek($ptr,"Begin")|out-null #step backward 
      $line = $sr.ReadLine() 
      $found=0 
      [email protected]() 
      [email protected]() 

      while ($line -ne $null){ #read to the end 
       $output+=$line 
       $found++ 
       $line=$sr.ReadLine() 
      } 
      if($found -ge $n){ #found enough lines 
       Write-Verbose "OK found $found/$n" 
       foreach($i in ($output.length - $n)..($output.length)){ #take only lines needed 
        $render+=$output[$i] 
       } 
       continue 

      } 
      else{ #move backward and retry to find lines 
       Write-Verbose "not enough line ($found displayed)" 
       $ptr-=$buffer 
       if ($ptr -le 0) { #eof without finding suffisant lines 
        $ptr=0 
        Write-host "not enough line ($found displayed)" 
        $render=$output 
       } 
      } 
     } 
    render $render 
    } 


    function tailFile($ptr){ 
     # return each line from the pointer position to the end of file 
     [email protected]() 
     $sr.BaseStream.Seek($ptr,"Begin")|out-null 
     $line = $sr.ReadLine() 
     while ($line -ne $null){ 
      $render+=$line 
      $line = $sr.ReadLine() 
     } 
     render $render 
    } 

    # Main loop 


    # use ReadWrite sharing permission to not lock the file 
    $fs=New-Object System.IO.FileStream ($filename,"OpenOrCreate", "Read", "ReadWrite",8,"None") 
    $sr=New-Object System.IO.StreamReader($fs, $enc) 
    $lastPosition=$sr.BaseStream.Length 

    tailFileBeforeEnd 

    if($continous){ 
     while(1){ 
      start-Sleep -s 2 
      # has the file changed ? 
      if ($sr.BaseStream.Length -eq $lastPosition){ 
       write-verbose "no change..." 
       continue 
      } 
      else { 
       tailfile $lastPosition 
       $lastPosition = $sr.BaseStream.Position 
       write-Verbose "new position $lastPosition" 
      } 
     } 
    } 
    $sr.close() 
} 
1

你可以看一下在PSCX Get-FileTail實施here但它不處理Unicode的。我相信還有其他一些可以改進的方法。 :-)建議歡迎。

+0

謝謝基思 –

+0

所以什麼認爲專家?它是否正確處理unicode? –