【问题标题】:Looking for a better way to write CSVs寻找一种更好的方式来编写 CSV
【发布时间】:2016-09-12 00:49:40
【问题描述】:

我编写了几个 PowerShell 脚本来从 Windows 机器上收集一些统计信息。第一个是关于以特定间隔收集 CPU、内存使用情况等。哪个工作正常。我写了另一个基本上检查文件的 lastaccesstime 并创建一个 CSV,代码如下:

$dest="C:\users\Administrator\Documents\filelist.csv"
$csvdata=@()
$source="x:\"
$count=0

Get-ChildItem -Recurse $source | foreach{

$csvdata += New-Object PSObject -Property @{FileName=$_.FullName;DateAccessed=($_.LastAccessTime).ToShortDateString()}

$csvdata|Export-Csv $dest -notype

$count+=1
$count

}

好吧,如果我继续向$csvdata 添加内容并且仅在循环结束时导出文件,那么如果脚本由于某些错误或其他原因而结束,我可能会丢失数据。因此,我将其导出到循环中,如代码所示。但这也意味着$csvdata 的大小将不断增加,这意味着它的内存占用量可能会增长到兆字节甚至更多。

有没有办法将此数据转储到 CSV,清空 $csvdata 变量而不影响结果?希望这是有道理的。

【问题讨论】:

  • script ends due to some error or something - 到底发生了什么?我以为 PowerShell 在遇到错误后默认会继续执行脚本。
  • 它实际上并没有以错误结束。我的意思是我每次都将 CSV 文件保存在循环中,这样如果程序意外退出,我仍然在 csv 文件中有数据。如果我在循环后导出 csv,那么我可能会在这种行为中丢失数据。

标签: powershell logic export-to-csv


【解决方案1】:

注意:您当前问题中的代码很奇怪,因为它会在每次通过时使用已经存在的所有数据覆盖文件。对于一个小数据集,您可能没有注意到,但这仍然很糟糕。请继续阅读,看看您可以做些什么。

但这也意味着 $csvdata 的大小将不断增加,这意味着它的内存占用可能会增长到兆字节甚至更多。

这里有几个问题。首先是你如何构建$csvdata。使用+= 将破坏数组并使其变大一个元素。这是一项成本高昂的操作,并会产生性能问题。您应该能够使用管道来完成您需要的事情(基于我们在这里看到的很少内容。)

Get-ChildItem -Recurse $source | foreach{

    New-Object PSObject -Property @{FileName=$_.FullName;DateAccessed=($_.LastAccessTime).ToShortDateString()} | 
        $csvdata | Export-Csv $dest -NoTypeInformation -Append

    $count+=1
    $count
}

您没有理由存储$csvdata,所以不要费心去做。继续讨论你的另一个问题。

如果您必须存储它并且您期望大型数据集,请考虑改用 .Net arraylist 类型。 真的使用中的基本示例

$csvData  = New-Object System.Collections.ArrayList

0..9 | ForEach-Object{
    [void]($csvData.Add([pscustomobject]@{Number=$_;Even=!($_%2)}))
}

$csvData | ExportTo-Csv -NoTypeInformation

如果脚本由于某些错误或其他原因而结束,我可能会丢失数据。

这似乎是您提出问题的主要原因。您担心在此过程中会丢失数据。我将不得不对您的示例含糊其辞,但您正在尝试解决我认为的错误问题。您应该担心错误处理,而不是试图找到更具弹性的导出过程。

如果存在代码故障的可能性,您应该考虑使用try{}catch{} 块以及-ErrorAction 的通用 cmdlet 参数。两者都有自己的位置,具体取决于您处理的是终止错误还是非终止错误。

在失败的地方使用那些将防止您的整个过程处于不完整或有问题的状态。

【讨论】:

  • 谢谢。我的问题更多是关于我导出数据的方式。我知道我的 $csvdata += 方法不是最好的,但这是我知道它会起作用的唯一方法。您使用 -Append 关键字为它提供了完美的解决方案。非常感谢。
  • 举个例子说明这个小改动有多大的不同,当我在更新前运行它时,花了 3 个多小时才得到 25,000 个文件。更改后 1 分钟内超过 25,000 个。
【解决方案2】:

我认为没有部分导出 csv,但您可以将逗号分隔的值写为字符串并将它们附加到循环内的文件中:

$dest="C:\users\Administrator\Documents\filelist.csv"
$csvdata=@()
$source="x:\"
$count=0

"FileName,DateAccessed" | Set-Content $dest

Get-ChildItem -Recurse $source | foreach{

    "$($_.FullName),$($_.LastAccessTime.ToShortDateString())" | Add-Content $dest

$count+=1
$count
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 2014-10-21
    • 1970-01-01
    相关资源
    最近更新 更多