通过PowerShell

时间:2017-01-15 16:13:25

标签: powershell csv

背景
我一直在浏览Stack上的几个帖子,只能找到如何将一行数据添加到CSV文件中的答案" (特别是this one)。虽然它们很好,但它们仅涉及从内存中添加单个条目的特定情况。假设我要将100,000行添加到CSV文件中,那么如果每行将其写入文件,则查询速度将降低几个数量级。我想,将所有内容保存在内存中要快得多,一旦我构建了一个包含我要添加的所有数据的变量,只需将其写入文件。

现状
我有来自客户的日志文件,包含大约五十万行。其中一些行以日期时间和服务器使用的内存开头。为了更好地了解内存使用情况,我想使用此信息绘制内存使用情况。 (注意:是的,最好的解决方案是要求开发人员添加这些信息,因为我们需要这个信息很常见,但是因为我们还没有这个,所以我需要使用我得到的信息)

我能够读取日志文件,提取内容,创建两个名为$ timeStamp的变量和$ memoryUsage,用于查找所有相关条目。当我尝试将其添加到自定义PSObject时发生问题。似乎使用$csvObject += $newRow only adds a pointer to the $newRow variable而不是实际的行本身。这是我到目前为止的代码:

$header1 = "Time Stamp"
$header2 = "Memory Usage"

$csvHeaders = @"
$header1;$header2
"@

# The following two lines are a workaround to make sure that the $csvObject becomes a PSObject that matches the output I'm trying to achieve.
$csvHeaders | Out-File -FilePath $csvFullPath
$csvObject = Import-Csv -Path $csvFullPath -Delimiter ";"

foreach ($TraceFile in $traceFilesToLookAt) {
    $curTraceFile = Get-Content $TraceFile.FullName
    Write-Host "Starting on file: $($TraceFile.Name)`n"

    foreach ($line in $curTraceFile) {
        try {
            if (($line.Substring(4,1) -eq '-') -and ($line.Substring(7,1) -eq '-')) {
                $TimeStamp = $line.Split("|",4)[0]
                $memoryUsage = $($line.Split("|",4)[2]).Replace(",","")

                $newRow = New-Object PSObject -Property @{
                    $header1 = $TimeStamp;
                    $header2 = $memoryUsage
                }
                $reorderedRow = $newRow | Select-Object -Property $header1,$header2

                $reorderedRow | Export-Csv -Path $csvFullPath -Append -Delimiter ";"
            }
        } catch {
            Out-Null
        }

这样可以正常工作,因为每次在CSV文件中找到行时都会追加该行。问题是它效率不高。

结束目标
理想情况下,我希望用以下方法解决它:

$newRow = New-Object PSObject -Property @{
    $header1 = $TimeStamp;
    $header2 = $memoryUsage
}
$rowsToAddToCSV += $newRow 

然后在最后一步做一个:

$rowsToAddToCSV | Export-Csv -Path $csvFullPath -Append -Delimiter ";"

我无法为此创建任何形式的解决方法。除此之外,PowerShell告诉我op_Addition不是对象的一部分,我尝试导出的对象(行集合)与CSV文件等不匹配。

1 个答案:

答案 0 :(得分:1)

任何将数千个项目附加到循环中的数组都会导致执行效果不佳,因为每次附加项目时,都会重新创建数组,其大小增加1,所有现有项目都会被复制,并且然后将新项目放入新的空闲位置。

为什么你不能简单地做这样的事情有什么特别的原因?

$traceFilesToLookAt | ForEach-Object {
    Get-Content $_.FullName | ForEach-Object {
        if ($_.Substring(4, 1) -eq '-' -and $_.Substring(7, 1) -eq '-') {
            $line = $_.Split('|', 4)
            New-Object PSObject -Property @{
                'Time Stamp'   = $line[0]
                'Memory Usage' = $line[2].Replace(',', '')
            }
        }
    }
} | Export-Csv -Path $csvFullPath -Append -Delimiter ";"

正则表达式匹配可能是从输入文件中提取时间戳和内存使用情况的更优雅的方法,但我将把它作为练习留给你。