【问题标题】:Powershell - Write Hash table to file with an ArrayPowershell - 使用数组将哈希表写入文件
【发布时间】:2020-07-29 16:00:03
【问题描述】:

我想将一个哈希表写入一个文件,其中包含一个数组作为哈希表项之一。我的数组项被写出,但它包含 files=System.Object[]

注意 - 一旦成功,我会想反转这个过程并再次读回哈希表。

clear-host
$resumeFile="c:\users\paul\resume.log"
$files = Get-ChildItem *.txt
$files.GetType()
write-host
$types="txt"
$in="c:\users\paul"

Remove-Item $resumeFile -ErrorAction SilentlyContinue
$resumeParms=@{}
$resumeParms['types']=$types
$resumeParms['in']=($in)
$resumeParms['files']=($files)
$resumeParms.GetEnumerator() | ForEach-Object {"{0}={1}" -f $_.Name,$_.Value} | Set-Content $resumeFile
write-host "Contents of $resumefile"
get-content $resumeFile

结果

IsPublic IsSerial Name                                     BaseType                                                      
-------- -------- ----                                     --------                                                      
True     True     Object[]                                 System.Array                                                  

Contents of c:\users\paul\resume.log
files=System.Object[]
types=txt
in=c:\users\paul

【问题讨论】:

标签: arrays powershell hashtable


【解决方案1】:

直接的解决方法是创建自己的数组表示,方法是枚举元素并用, 分隔它们,将字符串值包含在'...' 中:

# Sample input hashtable. [ordered] preserves the entry order.
$resumeParms = [ordered] @{ foo = 42; bar = 'baz'; arr = (Get-ChildItem *.txt) }

$resumeParms.GetEnumerator() |
  ForEach-Object { 
    "{0}={1}" -f $_.Name, (
      $_.Value.ForEach({ 
       (("'{0}'" -f ($_ -replace "'", "''")), $_)[$_.GetType().IsPrimitive] 
      }) -join ','
    )
  }

并不是说这会将所有非原始 .NET 类型表示为 字符串,而是通过它们的 .ToString() 表示,这可能不够好,也可能不够好。

上面的输出类似于:

foo=42
bar='baz'
arr='C:\Users\jdoe\file1.txt','C:\Users\jdoe\file2.txt','C:\Users\jdoe\file3.txt'

有关创建*.psd1 文件的变体,请参阅底部部分,该文件以后可以使用Import-PowerShellDataFile 读回哈希表实例。


在文本文件中保存设置/配置数据的替代方案:

  • 如果您不介意依赖第三方模块

    • 考虑使用PSIni模块,该模块使用Windows初始化文件(*.ini)文件格式;有关用法示例,请参见 this answer

      • GitHub issue #9035 中提议向 PowerShell 本身添加对初始化文件的支持(从 7.0 开始不存在)。
    • 考虑使用 YAML 作为文件格式;例如,通过FXPSYaml 模块。

      • GitHub issue #3607 中提议将 YAML 文件支持添加到 PowerShell 本身(自 7.0 起不存在)。
  • Configuration 模块基于持久化的 PowerShell 散列表文字 提供了写入和读取 *.psd1 文件 的命令,如你可以在源代码中声明它们。

    • 或者,您可以修改顶部代码中的输出格式以自己生成此类文件,这样您就可以通过
      Import-PowerShellDataFile 将它们读回,如底部所示。

    • 从 PowerShell 7.0 开始,没有对 写入 的内置支持,例如表示;也就是说,没有互补的Export-PowerShellDataFile cmdlet。 但是,GitHub issue #11300 正在提议添加此功能。

  • 如果创建(大部分)纯文本文件不是必须

  • 在其支持的数据类型方面提供最大灵活性的解决方案是 Export-Clixml 创建的基于 XML 的 CLIXML 格式,正如 Lee Dailey 所建议的那样,其输出稍后可以读取Import-Clixml.
    但是,这种格式在类型保真度方面也有限制,如this answer 中所述。

  • 保存数据的 JSON 表示,正如 Lee 还建议的那样,通过 ConvertTo-Json / ConvertFrom-Json,是另一种选择,它可以提供比 XML 更人性化的输出,但仍然不如纯文本表示友好;值得注意的是,所有\ 字符。 in 文件路径必须在 JSON 中转义为 \\


编写一个可以用Import-PowerShellDataFile 读取的*.psd1 文件

在关于数据类型的规定限制内 - 本质上,任何不是数字或字符串的东西都会变成 string - 将顶部的代码修改为 相当容易将 PowerShell 哈希表文字表示写入*.psd1 文件,以便可以通过Import-PowerShellDataFile 将其作为[hashtable] 实例读回

如前所述,如果您不介意安装模块,请考虑 Configuration 模块,该模块内置了此功能。

# Sample input hashtable.
$resumeParms = [ordered] @{ foo = 42; bar = 'baz'; arr = (Get-ChildItem *.txt) }

# Create a hashtable-literal representation and save it to file settings.psd1
@"
@{
$(
  ($resumeParms.GetEnumerator() |
    ForEach-Object { 
      "  {0}={1}" -f $_.Name, (
        $_.Value.ForEach({ 
          (("'{0}'" -f ($_ -replace "'", "''")), $_)[$_.GetType().IsPrimitive] 
         }) -join ','
      )
    }
  ) -join "`n"
)
}
"@ > settings.psd1

如果您稍后阅读settings.psd1Import-PowerShellDataFile settings.psd1,您将获得一个[hashtable] 实例,您可以照常访问其条目并产生以下显示输出:

Name                           Value
----                           -----
bar                            baz
arr                            {C:\Users\jdoe\file1.txt, C:\Users\jdoe\file1.txt, C:\Users\jdoe\file1.txt}
foo                            42

注意条目(键)的顺序是如何保留的,因为哈希表条目本质上是无序的。

写入 *.psd1 文件时,您可以通过将输入哈希表 (System.Collections.Hashtable) 声明为 [ordered] 来保留密钥 (-creation) 顺序,如上所示(创建一个 @ 987654341@ 实例),但不幸的是,在 读取*.psd1 文件时,订单丢失了。

从 PowerShell 7.0 开始,即使您将 [ordered] 放在打开 @{ 之前*.psd1 文件中Import-PowerShellDataFile 也会悄悄地忽略它并创建一个 无序 em> 仍然是哈希表。

【讨论】:

    猜你喜欢
    • 2013-02-05
    • 2015-07-21
    • 1970-01-01
    • 2021-12-10
    • 2016-06-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-19
    • 2021-08-13
    相关资源
    最近更新 更多