【问题标题】:Seek method not working in Powershell script寻求方法在 Powershell 脚本中不起作用
【发布时间】:2011-09-01 11:10:44
【问题描述】:

我正在尝试使用 .net API 来查找大型数据文件。由于某种原因,我无法使其工作。 这是我的代码:

function check_logs{
  $pos = 8192
  $count = 1
  $path = 'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Log\ERRORLOG.2'
  $br = 0
  $reader = [System.IO.File]::OpenText($path)
  $reader.DiscardBufferedData()
  $reader.BaseStream.Seek(0, [System.IO.SeekOrigin]::Begin)
    for(;;){
    $line = $reader.ReadLine()
    if($line -ne $null){$br = $br + [System.Text.Encoding]::UTF8.GetByteCount($line)}
    if($line -eq $null -and $count -eq 0){break}
    if($line -eq $null){$count = 0}
    elseif($line.Contains('  Error:')){
        Write-Host "$line  $br"
    }
}

}

如果我使用 0 作为 seek 方法的参数,它会按预期从头开始搜索,但它也会在写入读取的行之前将 0 写入控制台。示例:

 0
 2011-08-31 09:26:36.31 Logon       Error: 17187, Severity: 16, State: 1.  4101
 2011-08-31 09:26:36.32 Logon       Error: 17187, Severity: 16, State: 1.  4489
 2011-08-31 09:26:38.25 Logon       Error: 17187, Severity: 16, State: 1.  4929
 2011-08-31 09:26:38.25 Logon       Error: 17187, Severity: 16, State: 1.  5304
 2011-08-31 09:26:43.75 Logon       Error: 17187, Severity: 16, State: 1.  6120

如果我尝试使用 4096 而不是 0 它只会写出:

4096

我原以为除了前两行之外,它会写出与第一行相同的行。

有人能看出问题吗?我有另一个问题让我想到了这个。更多背景见this

编辑:仍在尝试解决这个问题。有谁知道我还能在哪里找到有关此问题的信息?是否可以向 Microsoft 脚本专家发送问题?

最好的问候

吉斯利

【问题讨论】:

    标签: .net powershell file-io seek


    【解决方案1】:

    Seek 方法返回流中的新位置,这就是打印数字的原因。

    至于为什么你没有得到输出:

    1. 确认文件大小大于 4K。
    2. 尝试打印所有行,而不仅仅是其中包含“错误”一词的行。这可能会给你一个线索
    3. StreamReader 是基本流周围的缓冲包装器,因此 Seek 和 Position 可能不会像您预期的那样工作。考虑http://geekninja.blogspot.com/2007/07/streamreader-annoying-design-decisions.html。尝试添加对$reader.DiscardBufferedData()的调用搜索之前。

    【讨论】:

    • @RB - 感谢您的回复。我使用什么而不是 0 并不重要,如果我输入 1,则输出为 1。此外,如果您在我使用 0 时查看输出,则最后一个数字应该是读取的字节数。或者至少我认为是……
    • 没错。 Seek 正在返回您寻求的偏移量。因此,如果您寻求 1234,它将返回 1234。请参阅msdn.microsoft.com/en-us/library/system.io.stream.seek.aspx中的“返回值”
    • @RB - 好的,这解释了很多。我认为它会将我移动到流中的特定位置。那么如何让读取从那个位置开始呢?
    • @Gisli。不太确定,但我认为在查找之后调用 DiscardBufferedData 将强制 StreamReader 从查找位置重新填充缓冲区,从而为您提供所需的内容。
    • 啊 - 本文建议将其称为 before 搜索,实际上更有意义!两者都试一下,让我知道哪个有效:) msdn.microsoft.com/en-us/library/…
    【解决方案2】:

    所以我终于找到了答案。由于某种我不知道的原因,我必须使用二进制阅读器。 下面是我的完整功能:

     function check_logs{
     Write-Host "New test `n`n"
     $pos = 19192
     $path = 'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Log\ERRORLOG.2'
     $br = 0
     $b = new-object System.IO.BinaryReader([System.IO.File]::Open($path,[System.IO.FileMode]::Open));
     $required = $b.BaseStream.Length - $pos
     $b.BaseStream.Seek($pos, [System.IO.SeekOrigin]::Begin)
     $bytes = $b.ReadBytes($required)
     $log = [System.Text.Encoding]::Unicode.GetString($bytes)
     $split = $log.Split("`n")
     foreach($s in $split)
     {
         if($s.contains("  Error:"))
         {
             Write-Host $s  "`n"
         }
     }
     $b.close
     }
    

    感谢您的帮助

    吉斯利

    【讨论】:

    • 问题来自文本的解释方式。您似乎很幸运,因为底层文件数据是单字节编码。您的解决方案不适用于 Unicode,并且有时仅适用于其中包含非“英文”字符的 UTF-8 文件。
    【解决方案3】:

    我遇到了类似的问题。寻找的位置正在控制台上打印。我只需要将返回值分配给某个变量,就解决了问题。

    所以而不是:

    $reader.BaseStream.Seek(0, [System.IO.SeekOrigin]::Begin)
    

    我不得不写这样的东西:

    $pos = $reader.BaseStream.Seek(0, [System.IO.SeekOrigin]::Begin)
    

    问候, Thejasvi V

    【讨论】:

      猜你喜欢
      • 2020-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-11
      相关资源
      最近更新 更多