Seek method not working in Powershell script
I´m trying to use the .net API to seek in a large data file. For some reason I am unable to make it work. Here is my code:
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"
}
}
}
If I use 0 as a parameter for the seek method it seeks from the beginning as expected but it also writes 0 out to the console before it writes the lines read. Example:
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 开发者_如何学Python Error: 17187, Severity: 16, State: 1. 6120
If I try to seek using 4096 instead of 0 it only writes out:
4096
I would have thought it would write out the same lines as the first one did apart from the first two.
Can someone see the problem? I had another question that got me to this. For further background see this
EDIT: Still trying to figure this out. Does anyone know where else I could try to find information regarding this problem? Is it possible to send questions to the Microsoft scripting guy?
Best regards
Gísli
The Seek method returns the new position within the stream, which is why you are having a number printed out.
As to why you are not getting an output:
- Confirm the file is greater than 4K in size.
- Try printing out all lines, rather than just lines with the word "Error" in them. That might give you a clue
- StreamReader is a buffered wrapper around the base stream, so Seek and Position may not work quite like you expect. Consider http://geekninja.blogspot.com/2007/07/streamreader-annoying-design-decisions.html. Try adding in a call to
$reader.DiscardBufferedData()
before the seek.
So I finally found the answer. For some reason unknown to me I have to use a binary reader. Here below is my complete function:
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
}
Thanks for the help
Gísli
I had a similar problem. The seeked-off position was getting printed on the console. I just had to assign the return value to some variable, and that solved the problem.
So instead of:
$reader.BaseStream.Seek(0, [System.IO.SeekOrigin]::Begin)
I had to write something like:
$pos = $reader.BaseStream.Seek(0, [System.IO.SeekOrigin]::Begin)
Regards, Thejasvi V
精彩评论