将哈希表导出到 CSV
Exporting Hashtable to CSV
我正在尝试编写一个 Powershell 脚本,它需要几个非常长的 space-separated 文件并将一些列导出到 similarly-named CSV 文件。
我有一个成功的版本:
Foreach ($file in $files) {
$WriteString=""
$outfile = $path + "\" + ($file -replace ".{4}$") + ".csv"
Get-Content -Path $path"\"$file | Select-Object -Skip $lines | ForEach-Object{
$ValueArray = ($_ -split "\s+")
$WriteString += $ValueArray[1] + "," + $ValueArray[2] + "," + $ValueArray[3] + "`n"
}
Add-Content -Path $outfile -Value $Writestring
}
这有效,但速度极慢 - 脚本完全 运行 需要 16 多个小时。主要原因(我认为)是添加到字符串中。我尝试使用哈希表改进它:
Foreach ($file in $files) {
$outfile = $path + "\" + ($file -replace ".{4}$") + ".csv"
$ParseLines = Get-Content -Path $path"\"$file | Select-Object -Skip $lines
$OutputData = ForEach ($Line in $ParseLines) {
$ValueArray = ($Line -split "\s+")
$Line | Select-Object $ValueArray[1], $ValueArray[2], $ValueArray[3]
}
$OutputData | Export-CSV -Path $outfile #-NoTypeInformation
}
但是,这只是导出哈希表的一行:
#TYPE Selected.System.String
"636050.000","7429825.000","77.438"
,,
,,
,,
,,
,,
,,
如果我将最后一行更改为:
Set-Content -Path $outfile -Value $OutputData
则输出变为:
@{636050.000=; 7429825.000=; 77.438=}
@{636075.000=; 7429825.000=; 75.476=}
@{636100.000=; 7429825.000=; 74.374=}
@{636125.000=; 7429825.000=; 73.087=}
@{636150.000=; 7429825.000=; 71.783=}
@{636175.000=; 7429825.000=; 70.472=}
我显然在处理哈希表或 Export-CSV 时做错了什么,但我无法弄清楚。任何帮助将不胜感激。
根据下面的要求,这是一个源文件的一部分。我删除了所有 non-data 行,并且不在我的输出 CSV 中包含 headers,因为输入程序(CSV 文件进入的程序)不需要它们,并且输出是 self-evident(仅通过查看数据就不太可能弄错 X、Y 和 Z 值)。
*
* DEFINITION
* HEADER_VARIABLES 3
* QUALITIES C 16 0 key
* DATE C 12 0
* TIME C 12 0
* VARIABLES 4
* X F 12 3
* Y F 12 3
* Z F 12 3
* gcmaq0.drg F 12 3
*
* 1 2 3 4
*23456789012345678901234567890123456789012345678
* X| Y| Z| gcmaq0.drg|
*
* HEADER:QUALITIES 29Aug2018 13:53:16
636575.000 7429800.000 75.551 75.551
636600.000 7429800.000 77.358 77.358
636625.000 7429800.000 78.823 78.823
636650.000 7429800.000 80.333 80.333
636675.000 7429800.000 82.264 82.264
636700.000 7429800.000 84.573 84.573
636725.000 7429800.000 87.447 87.447
Export-Csv
处理对象。它需要属性和值 - 您提供的(根据 Set-Content
结果判断)是仅包含键的哈希表。
解决此问题的一种方法是创建一个对象并从每一行递增值。
Foreach ($file in $files) {
$outfile = $path + "\" + ($file -replace ".{4}$") + ".csv"
$ParseLines = Get-Content -Path $path"\"$file | Select-Object -Skip $lines
ForEach ($Line in $ParseLines) {
$ValueArray = ($Line -split "\s+")
[array]$OutputData += [pscustomobject]@{
header1 = $ValueArray[1]
header2 = $ValueArray[2]
header3 = $ValueArray[3]
}
}
$OutputData | Export-CSV -Path $outfile #-NoTypeInformation
}
如果您有非常大的文件,不确定这是否是最佳方式 - 我相信正则表达式大师可以想出更有效的方法。
避免缓慢的操作,例如在循环中附加到字符串(或数组)。改变这个:
Get-Content -Path $path"\"$file |
Select-Object -Skip $lines |
ForEach-Object {
$ValueArray = ($_ -split "\s+")
$WriteString += $ValueArray[1] + "," + $ValueArray[2] + "," + $ValueArray[3] + "`n"
}
Add-Content -Path $outfile -Value $Writestring
进入这个:
Get-Content -Path "${path}${file}" |
Select-Object -Skip $lines |
ForEach-Object {
($_ -split "\s+")[1..3] -join ','
} |
Set-Content -Path $outfile
如果您确实想附加到现有文件,请将 Set-Content
替换为 Add-Content
。
上面Ansgar Wiechers worked best, but I also found a second way of doing it at this SO question.的解决方案是用一个ArrayList来存储hashtable,然后写入ArrayList。这种方法几乎但不如 Ansgar 的解决方案快。 (比字符串方法快 10 倍,正则表达式方法快 12 倍)
Foreach ($file in $files) {
[System.Collections.ArrayList]$collection = New-Object System.Collections.ArrayList($null)
$outfile = $path + "\" + ($file -replace ".{4}$") + ".csv"
$ParseLines = Get-Content -Path $path"\"$file | Select-Object -Skip $lines
$OutputData =@{}
ForEach ($Line in $ParseLines) {
$ValueArray = ($Line -split "\s+")
$OutputData.Easting = $ValueArray[1]
$OutputData.Northing = $ValueArray[2]
$OutputData.ZValue = $ValueArray[3]
$collection.Add((New-Object PSObject -Property $OutputData)) | Out-Null
}
$collection | Export-CSV -Path $outfile -NoTypeInformation
}
我正在尝试编写一个 Powershell 脚本,它需要几个非常长的 space-separated 文件并将一些列导出到 similarly-named CSV 文件。
我有一个成功的版本:
Foreach ($file in $files) {
$WriteString=""
$outfile = $path + "\" + ($file -replace ".{4}$") + ".csv"
Get-Content -Path $path"\"$file | Select-Object -Skip $lines | ForEach-Object{
$ValueArray = ($_ -split "\s+")
$WriteString += $ValueArray[1] + "," + $ValueArray[2] + "," + $ValueArray[3] + "`n"
}
Add-Content -Path $outfile -Value $Writestring
}
这有效,但速度极慢 - 脚本完全 运行 需要 16 多个小时。主要原因(我认为)是添加到字符串中。我尝试使用哈希表改进它:
Foreach ($file in $files) {
$outfile = $path + "\" + ($file -replace ".{4}$") + ".csv"
$ParseLines = Get-Content -Path $path"\"$file | Select-Object -Skip $lines
$OutputData = ForEach ($Line in $ParseLines) {
$ValueArray = ($Line -split "\s+")
$Line | Select-Object $ValueArray[1], $ValueArray[2], $ValueArray[3]
}
$OutputData | Export-CSV -Path $outfile #-NoTypeInformation
}
但是,这只是导出哈希表的一行:
#TYPE Selected.System.String
"636050.000","7429825.000","77.438"
,,
,,
,,
,,
,,
,,
如果我将最后一行更改为:
Set-Content -Path $outfile -Value $OutputData
则输出变为:
@{636050.000=; 7429825.000=; 77.438=}
@{636075.000=; 7429825.000=; 75.476=}
@{636100.000=; 7429825.000=; 74.374=}
@{636125.000=; 7429825.000=; 73.087=}
@{636150.000=; 7429825.000=; 71.783=}
@{636175.000=; 7429825.000=; 70.472=}
我显然在处理哈希表或 Export-CSV 时做错了什么,但我无法弄清楚。任何帮助将不胜感激。
根据下面的要求,这是一个源文件的一部分。我删除了所有 non-data 行,并且不在我的输出 CSV 中包含 headers,因为输入程序(CSV 文件进入的程序)不需要它们,并且输出是 self-evident(仅通过查看数据就不太可能弄错 X、Y 和 Z 值)。
*
* DEFINITION
* HEADER_VARIABLES 3
* QUALITIES C 16 0 key
* DATE C 12 0
* TIME C 12 0
* VARIABLES 4
* X F 12 3
* Y F 12 3
* Z F 12 3
* gcmaq0.drg F 12 3
*
* 1 2 3 4
*23456789012345678901234567890123456789012345678
* X| Y| Z| gcmaq0.drg|
*
* HEADER:QUALITIES 29Aug2018 13:53:16
636575.000 7429800.000 75.551 75.551
636600.000 7429800.000 77.358 77.358
636625.000 7429800.000 78.823 78.823
636650.000 7429800.000 80.333 80.333
636675.000 7429800.000 82.264 82.264
636700.000 7429800.000 84.573 84.573
636725.000 7429800.000 87.447 87.447
Export-Csv
处理对象。它需要属性和值 - 您提供的(根据 Set-Content
结果判断)是仅包含键的哈希表。
解决此问题的一种方法是创建一个对象并从每一行递增值。
Foreach ($file in $files) {
$outfile = $path + "\" + ($file -replace ".{4}$") + ".csv"
$ParseLines = Get-Content -Path $path"\"$file | Select-Object -Skip $lines
ForEach ($Line in $ParseLines) {
$ValueArray = ($Line -split "\s+")
[array]$OutputData += [pscustomobject]@{
header1 = $ValueArray[1]
header2 = $ValueArray[2]
header3 = $ValueArray[3]
}
}
$OutputData | Export-CSV -Path $outfile #-NoTypeInformation
}
如果您有非常大的文件,不确定这是否是最佳方式 - 我相信正则表达式大师可以想出更有效的方法。
避免缓慢的操作,例如在循环中附加到字符串(或数组)。改变这个:
Get-Content -Path $path"\"$file |
Select-Object -Skip $lines |
ForEach-Object {
$ValueArray = ($_ -split "\s+")
$WriteString += $ValueArray[1] + "," + $ValueArray[2] + "," + $ValueArray[3] + "`n"
}
Add-Content -Path $outfile -Value $Writestring
进入这个:
Get-Content -Path "${path}${file}" |
Select-Object -Skip $lines |
ForEach-Object {
($_ -split "\s+")[1..3] -join ','
} |
Set-Content -Path $outfile
如果您确实想附加到现有文件,请将 Set-Content
替换为 Add-Content
。
上面Ansgar Wiechers worked best, but I also found a second way of doing it at this SO question.的解决方案是用一个ArrayList来存储hashtable,然后写入ArrayList。这种方法几乎但不如 Ansgar 的解决方案快。 (比字符串方法快 10 倍,正则表达式方法快 12 倍)
Foreach ($file in $files) {
[System.Collections.ArrayList]$collection = New-Object System.Collections.ArrayList($null)
$outfile = $path + "\" + ($file -replace ".{4}$") + ".csv"
$ParseLines = Get-Content -Path $path"\"$file | Select-Object -Skip $lines
$OutputData =@{}
ForEach ($Line in $ParseLines) {
$ValueArray = ($Line -split "\s+")
$OutputData.Easting = $ValueArray[1]
$OutputData.Northing = $ValueArray[2]
$OutputData.ZValue = $ValueArray[3]
$collection.Add((New-Object PSObject -Property $OutputData)) | Out-Null
}
$collection | Export-CSV -Path $outfile -NoTypeInformation
}