如何将哈希表数组存储在文本文件中,然后调用每个哈希表中给定键的所有值

How to store an array of hashtables in a text file and then call all of the values for a given key in each hashtable

我正在使用一个文本文件作为我正在开发的应用程序的后端。我首先开始将文本文件保留为人类可读的格式,但我认为最好不要格式化是没有意义的。

我现在在后端开发过程中正在创建一个单行哈希表,其中每个条目具有相同的键但不同的值。看起来合乎逻辑且易于使用。

这是文本文件中条目的模型:

@{'bName'='1xx'; 'bTotal'='1yy'; 'bSet'='1zz'}
@{'bName'='2xx'; 'bTotal'='2yy'; 'bSet'='2zz'}
@{'bName'='3xx'; 'bTotal'='3yy'; 'bSet'='3zz'}

如您所见,每个条目的键是相同的,但是,值将不同。 (值的数值和重复性质纯属巧合,只是为了模型而设置的。实际值不会以数值为导向,也不会像示例中那样重复。 )

我可以通过键入以下内容来访问键和值:

$hash = Get-Content .\Desktop\Test.txt | Out-String | iex

输出:

Name                    Value
----                    -----
bName                   1xx
bTotal                  1yy
bSet                    1zz
bName                   2xx
bTotal                  2yy
bSet                    2zz
bName                   3xx
bTotal                  3yy
bSet                    3zz

我最终想要做的是收集 bNamebTotalbSet 的每个值,以便我可以将每个值附加到单独的 WinForms ComboBox。 WinForms 部分很简单,我只是在从文本文件中的每个哈希表中获取值时遇到了一些问题。

我试过了:

$hash.Values | ?{$hash.Keys -contains 'bName'}

但不管管道中给定的 $hash.Key 匹配如何,它只是每隔 $hash.Value 打印一次。

我知道 $hash 是一个数组,我想我可能必须在 foreach ($hash | %{}) 循环中输出每个迭代,但我不太确定这样做的正确方法。例如,当我尝试:

$hash | $_.Keys

$hash | $_.Values

它不会像处理哈希表那样对待每次迭代。

我在这里做错了什么?我是否以一种复杂的方式来处理它,而有一种更简单的方法来完成它?我乐于接受各种想法或建议。


事后想想:有趣的是,当你走开并将注​​意力转移到其他事情上时,一个显而易见的解决方案经常出现。

我去吃午饭了,我这辈子都无法理解为什么我没有意识到我可以很容易地做到这一点:

$hash.bName

或:

$hash.bTotal

或:

$hash.bSet

这完全符合我的要求。但是,考虑到所提供的答案,我可能会采用不同的方式使用 CSV 格式的 .ini 文件,而不是创建哈希表数组。

PowerShell 内置了 csv 处理功能,因此在这种情况下使用它是一个不错的选择。因此,假设您将数据存储在标准 csv 格式的文件中 headers:

"bName","bTotal","bSet"
"1xx","1yy","1zz"
"2xx","2yy","2zz"
"3xx","3yy","3zz"

然后像这样导入数据:

$data = Import-Csv $path

现在你有一个 PsCustomObject 数组,csv 文件中的每个 header 都是 object 的 属性。因此,例如,如果您想获得第二个 object 的 bTotal,您可以执行以下操作:

$data[1].bTotal

2yy

在文本文件中存储哈希表的一种方法是 INI format

[hashtable1]
bName=1xx
bTotal=1yy
bSet=1zz

[hashtable2]
bName=2xx
bTotal=2yy
bSet=2zz

[hashtable3]
bName=3xx
bTotal=3yy
bSet=3zz

INI 文件基本上是文本形式的哈希表的哈希表。它们可以读作 :

$ht = @{}
Get-Content 'C:\path\to\hashtables.txt' | ForEach-Object {
  $_.Trim()
} | Where-Object {
  $_ -notmatch '^(;|$)'
} | ForEach-Object {
  if ($_ -match '^\[.*\]$') {
    $section = $_ -replace '\[|\]'
    $ht[$section] = @{}
  } else {
    $key, $value = $_ -split '\s*=\s*', 2
    $ht[$section][$key] = $value
  }
}

写成这样:

$ht.Keys | ForEach-Object {
  '[{0}]' -f $_
  foreach ($key in $ht[$_].Keys) {
    '{0}={1}' -f $key, $ht[$_][$key]
  }
} | Set-Content 'C:\path\to\hashtables.txt'

可以像这样访问这种哈希表的哈希表中的各个值:

$ht['section']['key']

或者像这样:

$ht.section.key

另一种选择是将每个哈希表存储在单独的文件中

hashtable1.txt:

bName=1xx
bTotal=1yy
bSet=1zz

hashtable2.txt.

bName=2xx
bTotal=2yy
bSet=2zz

hashtable3.txt:

bName=3xx
bTotal=3yy
bSet=3zz

这将允许您通过 ConvertFrom-StringData:

将每个文件导入哈希表
$ht1 = Get-Content 'C:\path\to\hashtable1.txt' | Out-String |
       ConvertFrom-Stringdata

写文件基本上和上面一样(没有ConverTo-StringData cmdlet):

$ht1.Keys | ForEach-Object {
  '{0}={1}' -f $_, $ht[$_]
} | Set-Content 'C:\path\to\hashtables1.txt'