>我有一个 36 个 .log 文件的数据基础,我需要对其进行预处理,以便将它们加载到 pandas 数据框中,以便在 python 框架内进行数据可视化。
要提供其中一个.log文件中的单行示例,请执行以下操作:
[16:24:42]: Downloaded 0 Z_SYSTEM_FM traces from DEH, clients (282) from 00:00:00,000 to 00:00:00,000
从这里的几个来源和帖子中,我发现以下代码是性能最佳的代码:
foreach ($f in $files){
$date = $f.BaseName.Substring(22,8)
((Get-Content $f) -match "^.*bDownloadedb.*$") -replace "[[]", "" -replace "]:s", " "
-replace "Downloaded " -replace "Traces from " -replace ",.*" -replace "$", " $date"
| add-content CleanedLogs.txt
}
变量$date
包含日期,相应的.log文件正在记录。
我无法更改输入文本数据。我尝试使用 -raw 读取 1,55GB,但在处理所有操作后我无法拆分生成的单个字符串。此外,我尝试使用更多的正则表达式,但没有减少总运行时间。也许有一种方法可以使用 grep 进行此操作?
也许有人有一个天才的调整来加快此操作。目前,此操作需要近 20 分钟的时间来计算。谢谢!
提高性能的关键是:
- 避免使用管道和 cmdlet,尤其是对于文件 I/O (
Get-Content
、Add-Content
(- 请改用
System.IO.File
类型的方法。
- 请改用
- 避免在 PowerShell 代码中循环。
- 相反,链接阵列感知运算符,如
-match
和-replace
- 您已经在这样做了。 - 整合您的正则表达式以减少
-replace
调用。 - 使用预编译的正则表达式。
- 相反,链接阵列感知运算符,如
总而言之:
# Create precompiled regexes.
# Note: As written, they make the matching that -replace performs
# case-*sensitive* (and culture-sensitive),
# which speeds things up slightly.
# If you need case-*insensitive* matching, use option argument
# 'Compiled, IgnoreCase' instead.
$reMatch = New-Object regex 'bDownloadedb', 'Compiled'
$reReplace1 = New-Object regex 'Downloaded |Traces from |[', 'Compiled'
$reReplace2 = New-Object regex ']:s', 'Compiled'
$reReplace3 = New-Object regex ',.*', 'Compiled'
# The platform-appropriate newline sequence.
$nl = [Environment]::NewLine
foreach ($f in $files) {
$date = $f.BaseName.Substring(22,8)
# Read all lines into an array, filter and replace, then join the
# resulting lines with newlines and append the resulting single string
# to the log file.
[IO.File]::AppendAllText($PWD.ProviderPath + '/CleanedLogs.txt',
([IO.File]::ReadAllLines($f.FullName) -match
$reMatch -replace
$reReplace1 -replace
$reReplace2, ' ' -replace
$reReplace3, " $date" -join
$nl) + $nl
)
}
请注意,每个文件必须作为一个行数组整体放入内存中,再加上其中的一部分(作为数组和单个多行字符串(,其大小取决于筛选的行数。
我过去也有类似的问题。长话短说,直接使用 .NET 在使用大型文件时要快得多。您可以通过阅读性能注意事项来了解更多信息。
最快的方法可能是使用 IO.FileStream
.例如:
$File = "C:Path_To_FileLogs.txt"
$FileToSave = "C:Path_To_Fileresult.txt"
$Stream = New-Object -TypeName IO.FileStream -ArgumentList ($File), ([System.IO.FileMode]::Open), ([System.IO.FileAccess]::Read), ([System.IO.FileShare]::ReadWrite)
$Reader = New-Object -TypeName System.IO.StreamReader -ArgumentList ($Stream, [System.Text.Encoding]::ASCII, $true)
$Writer = New-Object -TypeName System.IO.StreamWriter -ArgumentList ($FileToSave)
while (!$Reader.EndOfStream)
{
$Box = $Reader.ReadLine()
if($Box -match "^.*bDownloadedb.*$")
{
$ReplaceLine = $Box -replace "1", "1234" -replace "[[]", ""
$Writer.WriteLine($ReplaceLine)
}
}
$Reader.Close()
$Writer.Close()
$Stream.Close()
您应该能够非常轻松地根据需要编辑上面的代码。要获取文件列表,您可以使用Get-ChildItem。
另外,我建议您阅读此堆栈溢出帖子。
也许这会加快您的速度:
$outFile = Join-Path -Path $PSScriptRoot -ChildPath 'CleanedLogs.txt'
$files = Get-ChildItem -Path '<YOUR ROOTFOLDER>' -Filter '*.txt' -File
foreach ($f in $files){
$date = $f.BaseName.Substring(22,8)
[string[]]$lines = ([System.IO.File]::ReadAllLines($f.FullName) | Where-Object {$_ -match '^.*bDownloadedb.*$'} | ForEach-Object {
($_ -replace '[|Downloaded|Traces from|,.*', '' -replace ']:s', ' ' -replace 's+', ' ') + " $date"
})
[System.IO.File]::AppendAllLines($outFile, $lines)
}