我想使用System.IO命名空间中的FileStream而不是Get-Content cmdlet。如何操作?
谢谢,
$fromaddress = "filemon@contoso.com"
$emailto = "IT@contoso.com"
$SMTPSERVER = "xx.xx.xx.xx"
$global:FileChanged = $false
$folder = "C:\temp"
$filter = "log.log"
$watcher = New-Object IO.FileSystemWatcher $folder,$filter -Property @{ IncludeSubdirectories = $false EnableRaisingEvents = $true }
Register-ObjectEvent $Watcher "Changed" -Action {$global:FileChanged = $true} > $null
while ($true)
{
while ($global:FileChanged -eq $false){
Start-Sleep -Milliseconds 100
}
if($(Get-Content -Tail 1 -Path $folder\$filter).Contains("Finished."))
{
Send-mailmessage -from $fromaddress -to $emailto -subject "Log changed" -smtpServer $SMTPSERVER -Encoding UTF8 -Priority High
}
# reset and go again
$global:FileChanged = $false
}
编辑1:
$fromaddress = "filemon@contoso.com"
$emailto = "IT@contoso.com"
$SMTPSERVER = "xx.xx.xx.xx"
$global:FileChanged = $false
$folder = "C:\tmp"
$filter = "log.log"
$watcher = New-Object IO.FileSystemWatcher $folder,$filter -Property @{ IncludeSubdirectories = $false ; EnableRaisingEvents = $true }
Register-ObjectEvent $Watcher "Changed" -Action {$global:FileChanged = $true} > $null
function Read-LastLine ([string]$Path) {
# construct a StreamReader object
$reader = [System.IO.StreamReader]::new($path)
$lastLine = ''
while($null -ne ($line = $reader.ReadLine())) {
$lastLine = $line
}
# clean-up the StreamReader
$reader.Dispose()
# return the last line of the file
$lastLine
}
while ($true)
{
while ($global:FileChanged -eq $false){
Start-Sleep -Milliseconds 100
}
$logFile = $Event.SourceEventArgs.FullPath
if ((Read-LastLine -Path $logFile) -match "Finished.")
{
write-host "mail sending"
Send-mailmessage -from $fromaddress -to $emailto -subject "Log changed" -smtpServer $SMTPSERVER -Encoding UTF8 -Priority High
}
# reset and go again
$global:FileChanged = $false
}
留言:
MethodInvocationException: C:\monfile.ps1:15
Line |
15 | $reader = [System.IO.StreamReader]::new($path)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Exception calling ".ctor" with "1" argument(s): "The value cannot be an empty string. (Parameter 'path')"
InvalidOperation: C:\monfile.ps1:17
Line |
17 | while($null -ne ($line = $reader.ReadLine())) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
| You cannot call a method on a null-valued expression.
InvalidOperation: C:\monfile.ps1:22
Line |
22 | $reader.Dispose()
| ~~~~~~~~~~~~~~~~~
| You cannot call a method on a null-valued expression.
4条答案
按热度按时间dauxcl2d1#
不确定这是否会比使用
Get-Content -Tail 1
更快,但您可以创建一个帮助函数,使用StreamReader返回文件中的最后一行。编辑
当事件发生时,您的代码并没有真正响应该事件,但似乎依赖于一个名为
FileChanged
的全局变量,您在while循环中测试了该变量。FileSystemWatcher的神奇之处在于,如果
log.log
文件中发生了更改,您可以坐下来休息,直到所选事件触发。只有当这样的事件发生时,才会执行Action
参数中定义的脚本块,因此这里使用helper函数重写代码以读取日志文件的最后一行。(自从我早期的回答,我已经改变了该函数,只检索最后一行,不是空的或空白)
当不再需要监视文件时,请注销事件并释放监视器
b91juud32#
尝试以下操作:
b4qexyjb3#
否
IO.FileSystemWatcher
版本:在查找前面答案的参考文献时,我发现我创建的LogFileReader类基于C#代码How to read a log file which is hourly updated in c#?,它与原始代码中的代码非常相似。
这个LogFileWatcher类类似于前面的LogFileReader类,但只保留了基本的内容,并使用了一个
Dirty()
方法来指示何时有更多的行可用:示例使用,C#代码的混合体,以及前面回答中的代码:
另外,如果我没记错的话,是What's the least invasive way to read a locked file in C# (perhaps in unsafe mode)?给了我线索,最终找到了上面的代码链接。
ajsxfq5m4#
在阅读日志文件的最后一行时会遇到一个真实的的问题,那就是你怎么知道它一次只添加了一行或一个日志条目?你真正需要的是跟踪日志文件并在添加时只读取新内容的东西。我的解决方案是创建一个LogFileReader类。
在我创建的一个测试脚本中,我在脚本的顶部添加了以下几行代码,这些代码取自问题:
然后添加了这个实验性的LogFileReader类。我在过去几周的某个时候创建了这个类来解决这个问题。到目前为止,它运行得很好,我没有看到它抛出错误或有问题。但同样,它是实验性的,没有彻底测试。
对于此类:
1.使用文件的完整路径创建一个示例,您可以选择添加编码。如果没有提供编码,则UTF8是默认值。
1.如果您想在阅读新行之前读取整个文件,则调用
ReadLines()
或ReadText()
,否则,调用GoToEnd()
以跳过文件的当前内容。ReadLines()
返回一个字符串数组。如果你想一次一个地获取每一个新添加的行,使用这个。ReadText()
返回单个字符串。如果您希望所有新添加的内容作为单个字符串,请使用此。1.完成后,使用
Dispose()
释放StreamReader。**编辑:**将旧的Dispose()
方法替换为新方法,该方法从StreamReader的BaseStream属性中检索FileStream,释放StreamReader,然后释放FileStream。1.如果出于某种原因,在多次读取之后,您希望从头读取文件,请调用
GoToStart()
,然后下一次读取将获得整个文件的内容。1.这个类维护一个指向上次读取结束的指针,并且每次调用
ReadLines()
时,指针都会向前移动到当前读取的结束。下面的测试代码被添加到脚本的末尾。**编辑:**它现在已经注解掉了允许捕获Ctrl+C和Gracefully stopping in Powershell的代码。显然,
[console]::TreatControlCAsInput
在所有情况下都不可用,即使docs似乎没有给予足够的信息来解释它何时不可用。它还包括3个版本的新内容的阅读。一个foreach {}
版本与if
用于捕获“Finished.”行,以及2个注解掉的版本以给出示例用途。注解掉了
Send-mailmessage
行,并添加了一个额外的Write-Host "[$Line]"
用于测试目的。