如何使用 StreamWriter WriteLine 忽略行

How to Ignore lines with StreamWriter WriteLine

试图弄清楚如何忽略或停止使用 StreamWriter 将特定行写入文件。这是我正在使用的代码 :

$LogDir     = "c:\users\user" # Log file output directory
$PlinkDir   = "C:"            # plink.exe directory
$SerialIP   = "1.1.1.1"       # serial device IP address
$SerialPort = 10000           # port to log

function CaptureWeight {
    Start-Job -Name WeightLog -ScriptBlock {
        filter timestamp {
            $sw.WriteLine("$(Get-Date -Format MM/dd/yyyy_HH:mm:ss) $_")
        }

        try {
            $sw = [System.IO.StreamWriter]::new("$using:LogDir\WeightLog_$(Get-Date -f MM-dd-yyyy).txt")
            & "$using:PlinkDir\plink.exe" -telnet $using:SerialIP -P $using:SerialPort | TimeStamp
        }
        finally {
            $sw.ForEach('Flush')
            $sw.ForEach('Dispose')
        }
    }
}

$job = CaptureWeight     # For testing, save the job
Start-Sleep -Seconds 60  # wait 1 minute
$job | Stop-Job          # kill the job
Get-Content "$LogDir\WeightLog_$(Get-Date -f MM-dd-yyyy).txt" # Did it work?

输出是这样的:

05/09/2022_14:34:19   G+027800 lb
05/09/2022_14:34:20 
05/09/2022_14:34:20   G+027820 lb
05/09/2022_14:34:21 
05/09/2022_14:34:21   G+027820 lb
05/09/2022_14:34:22 
05/09/2022_14:34:22   G+027820 lb

没有时间戳,每隔一行都是空白。我有几行来清理日志,一行删除每隔一行,一行删除权重为零的行:

   Set-Content -Path "$LogDir\WeightLog_$(get-date -f MM-dd-yyyy).txt" -Value (get-content -Path "$LogDir\WeightLog_$(get-date -f MM-dd-yyyy).txt" | Where-Object { $i % 2 -eq 0; $i++ })

   Set-Content -Path "$LogDir\WeightLog_$(get-date -f MM-dd-yyyy).txt" -Value (get-content -Path "$LogDir\WeightLog_$(get-date -f MM-dd-yyyy).txt" | Select-String -Pattern '00000' -NotMatch)

如果文件太大,这些文件可能需要一段时间 运行,最好不要一开始就写这些文件。

谢谢!

编辑,这就是我最后的结果:

#****************Serial Scale Weight Logger********************

$LogDir     = "c:\ScaleWeightLogger\Logs"  # Log File Output Directory
$PlinkDir   = "c:\ScaleWeightLogger"       # plink.exe Directory
$SerialIP   = "1.1.1.1"     # Serial Device IP Address
$SerialPort = "10000"             # Serial Device Port to Log
$MakeWeight = "000\d\d\d"         # Minimum weight to log
[datetime]$JobEndTime = '23:58'   # "WeightLog" Job End Time
[datetime]$JobStartTime = '00:02' #Use '8/24/2024 03:00' for a date in the future
# https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_regular_expressions

function StartWeightCapture {
    Start-Job -Name WeightLog -ScriptBlock {
        filter timestamp {
            # Set Output Filter, Do Not Write Blank Lines or Weight Matching...
            if([string]::IsNullOrWhiteSpace($_) -or $_ -match $using:MakeWeight) {
                # skip it
                return 
        }
        # Set TimeStamp Format Filter
        $sw.WriteLine("$(Get-Date -Format MM/dd/yyyy_HH:mm:ss) $_")
    }
        try {
            # Set File Path, Set $true to Append
            $sw = [System.IO.StreamWriter]::new("$using:LogDir\WeightLog_$(Get-Date -f MM-dd-yyyy).txt", $true)
            # Keep Memory Buffer Clear After Writting
            $sw.AutoFlush = $true
            # Start plink, Filter Output, Append TimeStamp 
            & "$using:PlinkDir\plink.exe" -telnet $using:SerialIP -P $using:SerialPort | TimeStamp
        }
        finally {
            # Discard Data After Writing
            $sw.ForEach('Flush')
            $sw.ForEach('Dispose')
        }
    }
}

function WeightCaptureEndTime {
   [datetime]$CurrentTime = Get-Date
   [int]$WaitSeconds = ( $JobEndTime - $CurrentTime ).TotalSeconds
   Start-Sleep -Seconds $WaitSeconds
 }

 function StopWeightCapture {
     Stop-Job WeightLog
     $AddDaysWhenInPast = 1
     [datetime]$CurrentTime = Get-Date
     If ($JobStartTime -lt $CurrentTime) { $JobStartTime = $JobStartTime.AddDays($AddDaysWhenInPast) }
     [int]$WaitSeconds = ( $JobStartTime - $CurrentTime ).TotalSeconds
     Start-Sleep -Seconds $WaitSeconds
     
 }   

while ($true) {
    StartWeightCapture
    WeightCaptureEndTime 
    StopWeightCapture
}

我在启动时使用:

powershell -windowstyle hidden -ExecutionPolicy bypass "& "C:\ScaleWeightLogger\ScaleWeightLogger.ps1"" & exit

因为它在后台,所以手动结束它。它只获取主 powershell 进程的 PID 而不是作业:

@echo off
for /F "tokens=2" %%K in ('
   tasklist /FI "ImageName eq powershell.exe" /FI "Status eq Running" /FO LIST ^| findstr /B "PID:"
') do (
   echo "PID is %%K, Ending process..."
   taskkill /F /PID %%K
)

pause
exit

如果我理解正确的话,添加这个条件应该可以避免您不得不阅读日志并跳过不需要的行的麻烦。

详情见String.IsNullOrWhiteSpace(String) Method and -match matching operator

filter timestamp {
    # if this output is purely whitespace or it matches `00000` 
    if([string]::IsNullOrWhiteSpace($_) -or $_ -match '00000') {
        # skip it
        return 
    }
    $sw.WriteLine("$(Get-Date -Format MM/dd/yyyy_HH:mm:ss) $_")
}

关于上一个问题中提到的观察结果:

...when trying view the file while it's running, it seems like it updates (for viewing) about every 2 minutes, you get one 2 minute chunk of data that is about 2 minutes behind, the 2 minutes of data is there...

为此,您可以启用 AutoFlush property from your StreamWriter

Remarks 很好地解释了何时值得启用此 属性 以及性能影响:

When AutoFlush is set to false, StreamWriter will do a limited amount of buffering, both internally and potentially in the encoder from the encoding you passed in. You can get better performance by setting AutoFlush to false, assuming that you always call Close (or at least Flush) when you're done writing with a StreamWriter.

For example, set AutoFlush to true when you are writing to a device where the user expects immediate feedback. Console.Out is one of these cases: The StreamWriter used internally for writing to Console flushes all its internal state except the encoder state after every call to StreamWriter.Write.

$sw = [System.IO.StreamWriter]::new("$using:LogDir\WeightLog_$(Get-Date -f MM-dd-yyyy).txt")
$sw.AutoFlush = $true