Powershell为什么两个json内容之间存在差异?

icomxhvb  于 2023-06-07  发布在  Shell
关注(0)|答案(2)|浏览(175)

我有两个Byte[]类型的变量(我选择这个类型是为了特定的需要,所以需要保留它),它们声明为:

$first = New-Object Byte[] 32
$second = New-Object Byte[] 32

我初始化了两个变量的每个指数。
现在,我创建了一个hashtable $List1

$List1=@{"First" = $first; "Second" = $second}

我使用下面的语法来创建json文件:

$List1 | ConvertTo-Json | Set-Content  -Path $jsonFile1

这是json文件的第一个内容:

{
"First":  {
             "value":  [
                           210,
                           195,
                           131,
                           176,
                           88,
                           154,
                           57,
                           37,
                           2,
                           75,
                           182,
                           190,
                           156,
                           43,
                           113,
                           199,
                           63,
                           25,
                           109,
                           92,
                           220,
                           91,
                           219,
                           252,
                           113,
                           68,
                           202,
                           12,
                           147,
                           194,
                           36,
                           177
                       ],
             "Count":  32
         },
"Second":  {
           "value":  [
                         238,
                         225,
                         12,
                         172,
                         134,
                         94,
                         42,
                         204,
                         27,
                         78,
                         39,
                         166,
                         229,
                         111,
                         143,
                         254
                     ],
           "Count":  16
       }
}

然后我将第一个json文件读入一个临时变量,如下所示:

$tempHash = Get-Content -Path $jsonFile1 -Raw| ConvertFrom-Json

因为$tempHash是一个PSCustomObject,我创建了一个新的哈希表$List2,如下所示:

$List2 = @{"First" = $tempHash.First.value; "Second"= $tempHash.Second.value}

我用它来创建第二个json文件,如下所示:

$List2 | ConvertTo-Json | Set-Content  -Path $jsonFile2

这是第二个json文件内容:

{
"First":  [
             133,
             231,
             19,
             173,
             60,
             50,
             105,
             68,
             38,
             109,
             99,
             155,
             2,
             188,
             216,
             9,
             8,
             225,
             203,
             15,
             167,
             8,
             188,
             76,
             192,
             154,
             183,
             194,
             1,
             122,
             143,
             137
         ],
"Second":  [
           27,
           3,
           57,
           67,
           155,
           145,
           181,
           194,
           250,
           10,
           65,
           90,
           41,
           230,
           243,
           196
       ]
}

我使用相同的语法来创建这两个json文件。为什么它们的结构不同呢?

[编辑]

我怀疑,区别是因为这个语法:

$List1=@{"First" = $first; "Second" = $second}

因为Byte[]类型变量不能作为简单的integer[]类型变量工作。纠正我。

[编辑]

因此,Byte[]类型变量有两个不同的键。“value”保存字节值的实际数组,“Count”保存Byte[]变量中的元素数。但是,当我们调用Byte[]类型变量时,如下所示:

$first

类型为Byte[],我们只得到“value”键下列出的值。“count”键下的值永远不会显示在控制台中,但它会以某种方式传递给哈希表。
还有一点要注意。如果我用途:

$List2 = @{"First" = $tempHash.First; "Second"= $tempHash.Second}

那么,我将不得不用途:

$List2.First.Value #to get the value of the "First" key

这让我感到不舒服,因为对于$List1哈希表,我只需要用途:

$List1.First #to get the value of the "First" key.

[解决方法]

我创建了一个hastable $List作为原始哈希表,如下所示,严格***仅供一次性使用***:

$List | ConvertTo-Json | Set-Content  -Path $jsonFile

然后,我从上面的原始$jsonFile创建了两个hastable $List1$List2,如下所示。

$tempHash = Get-Content -Path $jsonFile -Raw| ConvertFrom-Json
 $List1 = @{"First" = $tempHash.First; "Second" = tempHash.Second}
 $List2 = @{"First" = $tempHash.First; "Second" = tempHash.Second}

它帮助我在引用它们的键和值时保持一致性。
现在,我用

#to fetch the values of the "First" keys of both hashtables.
$List1.First.value #and
$List2.First.value

类似地,我对哈希表$List1$List2的“Second”键做了同样的操作。

#to fetch the values of the "Second" keys of both hashtables.
$List1.Second.value #and
$List2.Second.value

[编辑]
原来是我的Powershell版本中的一个bug,由下面的@mklement0 stststed。完美的解决方案是按照@mklement0的指示使用下面的语法:

# Ensure that the input array is constructed without the extra [psobject] wrapper.
$First = [Byte[]]::new(32)
$Second = [Byte[]]::new(32)
hfyxw5xn

hfyxw5xn1#

      • 第一个ConvertTo-Json调用的结果是 * Windows PowerShell * 中的一个 * 怪癖 ,从v5.1开始:生成的JSON应该有FirstSecond包含一个数组 * 直接 * 而不是一个 * 对象 * 具有valueCount属性,value包含数组*。
  • 此行为已为fixed in PowerShell (Core) (v6+);它很可能不会在 * Windows * PowerShell中得到修复,该软件已不再积极开发,只接收关键修复程序。

$a = New-Object Byte[] 2; @{ a = $a } | ConvertTo-Json -Compress得到:

  • PowerShell Core v6.0.1中的{"a":[0,0]}-正常。
  • Windows PowerShell v5.1中的{"a":{"value":[0,0],"Count":2}}-已损坏。
  • 在你的例子中,是**New-Object的使用触发了怪癖
  • 最有可能的是它与this issue有关;但是,请注意,所述问题在PowerShell Core中也没有解决,但上面链接的修复程序解决了此上下文中的问题。
    • 解决方法**:

在脚本/会话开始时,运行:

Remove-TypeData System.Array

这将从所有数组对象中删除过时的ETS提供的.Count属性,这使得[psobject] Package 的对象(例如New-Object返回的对象)的问题消失-有关解释,请参阅this answer

    • 更繁琐的解决方法**:

如果您确保-is [psobject]不再为输入数组报告true,问题就会消失,这可以通过以下方式之一完成:

  • [PSv5 +]:$First = [Byte[]]::new(32)-使用 * expression * 而不是命令可以解决问题,因为它不会创建额外的不可见的[psobject] Package 器。
  • [PSv4-]:$First = (New-Object Byte[] 32).psobject.BaseObject-显式绕过额外的[psobject] Package 器使问题消失。
    • 简化示例**(PSv5+,但易于适应早期版本;省略文件操作,因为它们是问题的附带内容):
# Ensure that the input array is constructed without the extra [psobject] wrapper.
$First = [Byte[]]::new(2)

# Construct a hashtable...
$List1 = @{ First = $first }
# ... and convert it to JSON:
($json = $List1 | ConvertTo-Json)

现在上面正确地产生(* no * externally object with value and count properties):

{
    "First":  [
                  0,
                  0
              ]
}

将此JSON字符串重新转换为对象现在可以按预期工作:

# Re-convert: $tempObj.First then *directly* contains the input array
#             (there is no .Value property anymore).
$tempObj = $json | ConvertFrom-Json

# Construct a new hashtable...
$List2 = @{ First = $tempObj.First }
# ... and convert it to JSON.
$List2 | ConvertTo-Json

结果是与上面相同的JSON字符串。

lbsnaicq

lbsnaicq2#

更改此:

$List2 = @{"First" = $tempHash.First.value; "Second"= $tempHash.Second.value}

对此:

$List2 = @{"First" = $tempHash.First; "Second"= $tempHash.Second}

这将保持valuecount结构。在测试中,它还保持了value部分中的值的顺序。

编辑

为了增强您的解决方法,您可以放入此步骤,以便您可以访问值,而不必使用.value

$firstValues = [byte[]]($tempHash.First.value)
$secondValues = [byte[]]($tempHash.Second.value)

$List1 = @{"First" = $firstValues; "Second" = $secondValues}
$List2 = @{"First" = $firstValues; "Second" = $secondValues}

自包含测试脚本

$jsonFile1 = "jsonFile1.json"
$jsonFile2 = "jsonFile2.json"

$first = New-Object Byte[] 32
$second = New-Object Byte[] 16

foreach($i in 0..($first.COunt -1)){
    $first[$i] = Get-random -minimum 1 -maximum 254
}

foreach($i in 0..($second.COunt -1)){
    $second[$i] = Get-random -minimum 1 -maximum 254
}

$List = @{"First" = $first; "Second" = $second}
$List | ConvertTo-Json | Set-Content -Path $jsonFile1

$tempHash = Get-Content -Path $jsonFile1 -Raw | ConvertFrom-Json

$firstValues = [byte[]]($tempHash.First.value)
$secondValues = [byte[]]($tempHash.Second.value)

$List1 = @{"First" = $firstValues; "Second" = $secondValues}
$List2 = @{"First" = $firstValues; "Second" = $secondValues}

相关问题