【问题标题】:Import-Csv too Slow导入 CSV 太慢
【发布时间】:2018-09-13 10:38:22
【问题描述】:

我目前有一个 PowerShell 脚本,该脚本将导入 CSV 文件,然后过滤第一列以在该行超过特定时间时删除整行。但是,使用Import-Csv 需要很长时间。在不使用Import-Csv 的情况下,是否有其他方法可以达到相同的结果?

这是目前的脚本:

$files = Get-ChildItem "C:\Results\*.csv"

foreach ($file in $files) {
    $filename = [IO.Path]::GetFileNameWithoutExtension($file)
    $csv = Import-Csv $file

    $dateTime = $csv[0]."Date and Time"

    $startTime = $dateTime.Substring($dateTime.get_Length()-8)

    $endTime = $startTime
    [int]$hour, [int]$min, [int]$sec = $endTime.Split(':')

    $hour = $hour + 1
    $min = 44
    $sec = 59

    $csv | ForEach-Object {
        $lineTime = $_."Date and Time"
        $startTime = $lineTime.Substring($lineTime.get_Length()-8)
        $newHour, $newMin, $newSec = $startTime.Split(':')
        if (($newHour -lt $hour -and $newMin -gt $min) -or ($newHour -eq $hour -and $newMin -le $min)) {
            $_ | Export-Csv -Path "C:\PerfResults\NewFiles\$filename-NEW.csv" -Append 
        }
    }
}

编辑:

根据 Olaf 的要求,以下是 CSV 文件中的数据示例:

日期和时间 内存过量使用(1 分钟平均值) 内存过量使用(5 分钟平均值) 内存过量使用(15 分钟平均值) Cpu 负载(1 分钟平均值) Cpu 负载(5 分钟平均值) 负载(15 分钟平均值) 物理 Cpu(0)\ % 处理器时间 2018 年 7 月 24 日 14:45:03 0 0 0 0.11 0.13 0.11 7.31 2018 年 7 月 24 日 14:45:06 0 0 0 0.11 0.13 0.12 1.41

【问题讨论】:

  • 您也可以发布几行 csv 文件(也请格式化为代码 ;-))。当您首先在自定义对象中“收集”结果并在最后将其全部导出时,它可能会加快您的代码速度。使用 -Append 真的很慢,因为在后台进行必要的文件系统操作。
  • 感谢您的回复 Olaf,我正在使用的 csv 文件有大约 12500 列和 1800 行,因此发布行可能有点困难。
  • 因此,您应该将行缩短到相关列,并从中选择 3 或 4 行。当然,如果需要,您应该混淆敏感信息。
  • 我附上了文件包含的日期示例,不知道如何更改格式,以便每个数据条目显示在列名下。
  • CSV 中的 12500 列太疯狂了。为什么要使用 CSV 而不是数据库来保存这些数据?

标签: powershell import-csv


【解决方案1】:

当你处理 DateTime 对象时,你应该这样对待它们。您可以计算甚至比较它们比字符串更容易。我认为这会让你的生活更轻松。当您首先收集所需的所有数据然后将它们一次保存到文件中时,速度会更快。

$fileList = Get-ChildItem "C:\Results\*.csv"

foreach($file in $fileList) {
    $csv = Import-CSV -Path $file.FullName -Delimiter "`t"
    $NewData = foreach($Data in $csv){
        $Data |
            Select-Object -Property *,
                                    @{
                                        Name = 'NewDateAndTime';
                                        Expression = {
                                            $DateTime = [DateTime]::ParseExact($($Data.'Date and Time'),"MM/dd/yyyy HH:mm:ss",$null)
                                            $DateTime.AddHours(-4)
                                        }
                                    }
    }
    $NewData | Export-Csv -Path "C:\PerfResults\NewFiles\$($file.BaseName)-NEW.csv" -Delimiter "`t" -NoTypeInformation -Force
}

如果您在输出 csv 中不需要来自输入 csv 的所有数据,您可以使用 Select-Object 选择您需要的数据。

编辑:附加说明 - 我将“字符串”日期和时间从 csv 文件转换为具有计算属性的 DateTime 对象。然后我只减去了 4 个小时来展示如何使用 DateTime 对象进行计算。当然,您应该根据您的特殊需求对其进行调整。 ;-)

【讨论】:

  • 感谢您的回复。这些文件现在生成得更快,但是您提供的脚本与我的原始脚本创建的格式不匹配。在您的脚本中,它似乎将所有数据写入第一列,然后只写入 4 行,而不是将每个数据条目分隔到单独的单元格中。关于如何避免这种情况的任何想法?
  • 哎呀......你是对的。我忘记了-Delimiter。我更正了答案中的代码。现在就试试。我通常使用逗号作为分隔符...
  • 现在我已经在这个脚本中添加了分隔符并且格式正确,处理文件所需的时间没有区别。生成“-NEW”csv 文件仍需要约 4 分钟。是否有使用“Import-CSV”的替代方法? “获取内容”可能吗?
  • hmmm ... 4 分钟大约 12500 列和 1800 行对我来说听起来并没有那么糟糕。 ;-) 这真的重要吗?您必须等待它还是可以在后台自行运行?
  • 如果可能的话,我想比这更快地完成这个过程,我有 100 个文件要处理,这只是我需要执行的第一个过滤器,在我删除我做的时间行之后不需要,我还需要从文件中删除列。
猜你喜欢
  • 2017-06-07
  • 1970-01-01
  • 2019-09-25
  • 1970-01-01
  • 2022-01-14
  • 1970-01-01
  • 2015-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多