从一个700MB的json文件中,我如何列出PowerShell中的所有键?

rbl8hiat  于 10个月前  发布在  Shell
关注(0)|答案(2)|浏览(78)

我试

$obj = [System.IO.File]::ReadLines((Convert-Path -LiteralPath names.json)) | ConvertFrom-Json
 
$keys = @() 
 
foreach ($key in $obj.GetEnumerator()) { 
  $keys += $key.Key 
} 
 
Write-Output $keys

字符串
但24小时后,它还没有完成。
我需要钥匙的名字
1.删除不相关的信息,使其更小
1.将其转换为csv(键名称是必需的,否则PS只使用第一个对象并忽略第一个对象中不存在的键)
JSON是这个的一个版本(尽管小了200 megs):https://kaikki.org/dictionary/All%20languages%20combined/by-pos-name/kaikki_dot_org-dictionary-all-by-pos-name.json

rkkpypqq

rkkpypqq1#

您可以流式处理文件并处理每行,避免对大文件使用Get-Content,并最大限度地减少小文件调用的次数:

$allKeys = @{}

[System.IO.File]::ReadLines("names.json") | ForEach-Object {
    $obj = ConvertFrom-Json $_
    $obj.PSObject.Properties.Name | ForEach-Object {
        $allKeys[$_]= $true
    }
}

$uniqueKeys = $allKeys.Keys

Write-Output $uniqueKeys

字符串
这种方法使用.NET ReadLines方法来有效地流式传输文件并处理每一行。

我终于下载完了你的大JSON文件。

  • 为了进一步处理JSON,下面是从每行中提取的“注解”:
$allGlosses = @()

[System.IO.File]::ReadLines("sample.json") | ForEach-Object {
    $obj = ConvertFrom-Json $_
    $obj.senses.glosses | ForEach-Object {
        $allGlosses += $_
    }
}

Write-Output $allGlosses


这将给你一个给予每个JSON对象的注解列表。

反馈回复:

也许可以使用哈希表来存储唯一键,避免不必要地使用ForEach-Object,并使用完整路径进行文件访问:

$allKeys = @{}
$filePath = Resolve-Path "names.json"

foreach ($line in [System.IO.File]::ReadLines($filePath)) {
    $obj = ConvertFrom-Json $line
    foreach ($key in $obj.PSObject.Properties.Name) {
        $allKeys[$key] = $true
    }
}

$uniqueKeys = $allKeys.Keys

Write-Output $uniqueKeys


这段代码避免了使用+=增长数组,使用foreach循环而不是ForEach-Object,并在.NET方法中使用文件路径之前解析文件路径。

tvokkenx

tvokkenx2#

您已经在使用最有效的方法(在PowerShell中)来解析基于行的 JSONL 输入文件**(请参阅底部部分的解释)。
看起来您只是在**寻找ConvertFrom-Json解析JSON文档所生成的[pscustomobject]示例的 * 属性名 *。
注意事项:

  • 在下面的讨论中,$someObj表示一个 * 单个 * 对象,就像您基于代码使用$someObj = $obj[0]得到的对象一样,假定$obj包含一个(大)* 数组 * 对象;示例可视化使用来自linked file$obj[0]
  • JSONL输入文件中的不同对象可能有 * 不同的 * 属性。如果有,查找属性名的 * 共享集 * 将需要更多的努力。suchislife's answer展示了如何查找所有不同属性名的 union,即所有对象的所有 * 顶级 * 属性名;更简洁的解决方案是(输出属性名的排序列表):
$allTopLevelPropNames = 
  [Collections.Generic.SortedSet[string]] @(
    $obj | ForEach-Object { $_.psobject.Properties.Name }
  )

字符串
发现对象的 immediate(顶级)属性**的最简单方法是通过内部psobject属性:

$propNames = $someObj.psobject.Properties.Name


使用Get-Member是另一个选项(主要用于 * 显示 * 输出):

$someObj | Get-Member -Type Properties


然而,考虑到存储在$obj中的[pscustomobject]示例是对象 * 图 *,即每个示例都是 * 嵌套 * [pscustomobject] s的层次结构,您可能会对发现属性名称的 * 层次结构 * 感兴趣,即对象 * 结构

  • 如果你不介意定义一个 *helper函数 *,你可以使用this answer中的Get-LeafProperty函数,它将一个给定的[pscustomobject]表示为一个 * 属性路径-值对的列表 *;例如,$someObj | Get-LeafProperty产生如下内容:
NamePath                         Value
--------                         -----
pos                              name
head_templates[0].name           en-proper noun
head_templates[0].expansion      Abib
etymology_text                   From Hebrew אָבִיב (avív, literally “ears of barley”), hence “the season of beginning barley-crop”, because the grains start ripening at that tim…
etymology_templates[0].name      bor
etymology_templates[0].args.1    en
etymology_templates[0].args.2    he
etymology_templates[0].args.3    אָבִיב
etymology_templates[0].args.tr   avív
etymology_templates[0].args.lit  ears of barley
etymology_templates[0].expansion Hebrew אָבִיב (avív, literally “ears of barley”)

  • 一个 ad hoc 选项只是 * 重新转换为JSON*,使用ConvertTo-Json**,利用这样一个事实,即所得到的JSON表示 * 默认情况下打印得很漂亮 *(选择退出需要使用-Compress):
$someObj | ConvertTo-Json -Depth 5

  • 请注意,不幸的是,需要指定一个-Depth参数,该参数具有足够多的序列化级别,以避免截断(默认深度仅为2;有关详细信息,请参阅this post)。
  • 另一个特别的选项-仅用于显示输出 ,但输出的噪声比JSON小-是使用*Format-Custom**:
$someObj | Format-Custom

  • 你将得到一个层次化的显示,没有引号,很容易在视觉上解析。与所有Format-*小工具一样,输出仅用于 * 显示 *,不适合 * 编程 * 处理(参见this answer)。
  • Format-Custom的默认深度是5,所以在这种情况下不需要-Depth参数。
  • 虽然通常不需要了解对象图的整体结构及其属性 names,[1]但请注意,通常您可能需要(临时)设置$FormatEnumerationLimit首选项变量,以确保属性值中 collection(数组)的所有元素都是可视化的;默认情况下,只有 4 元素,省略的元素表示为

示例Format-Custom输出(删节):

class PSCustomObject
{
  pos = name
  head_templates = 
    [
      class PSCustomObject
      {
        name = en-proper noun
        expansion = Abib
      }
    ]
    
  etymology_text = From Hebrew אָבִיב (avív, literally “ears of barley”), hence “the season of beginning barley-crop”, because the grains start ripening at that time of year.
  etymology_templates = 
    [
      class PSCustomObject
      {
        name = bor
        args = 
          class PSCustomObject
          {
            1 = en
            2 = he
            lit = ears of barley
          }
        expansion = Hebrew אָבִיב (avív, literally “ears of barley”)
      }
    ]
    
  word = Abib
  lang = English
  lang_code = en

   …

}


基于上面发现的属性,下面是一个calculated property的例子,它从输入对象创建CSV数据:

# Sample CSV output - limited to 10 in this example.
$obj | 
  Select-Object -First 10 -Property word, 
                                    lang, 
                                    @{ n='glosses'; e={ $_.senses.glosses } } |
  ConvertTo-Csv -NoTypeInformation

高效处理JSONL文件:

suchislife找到了一个合适的术语来描述JSON输入数据的line-based 格式JSONL (JSON Lines format);也就是说,输入文件的*每一行 * 都是一个 self-contained JSON文档(这意味着文件 * 作为一个整体 * 不是 * 有效的JSON,因为缺少一个整体的封闭对象或数组)。

ConvertFrom-Json有内置的语法支持此类输入

    • 如果 * the first input object(string) 是一个 self-contained JSON document,那么它将被解析为一个自包含的JSON文档,并且所有后续的行都将被同样对待。否则,所有输入行将被 * 完整收集 ,然后 * 被解释为JSON, 一起 *(即,作为一个包含所有输入行的JSON文档)。
  • 顺便说一句:这种启发式方法在开始时有 * 空行 * 和 * 单行注解 * 的潜在缺陷-参见this answer

因此,正如你的问题所示,
[System.IO.File]::ReadLines((Convert-Path -LiteralPath names.json)) | ConvertFrom-Json):

*您可以将JSONL文件的行一行一行地 * 直接 * 传输到ConvertFrom-Json

  • 这比使用ForEach-Object调用要高效得多,在ForEach-Object调用中,ConvertFrom-Json每一行调用 * 一次 *。
  • 同样,对于JSONL输入,ConvertFrom-Json[pscustomobject] * 输出 * 对象 * 可用时 *(即,在解析给定输入行之后)对其进行流传输。
  • 和**执行此流 * 有效地与一个大的输入文件 [System.IO.File]::ReadLines()是(目前)需要*.
  • Convert-Path用于确保传递 * 完整 * 路径,因为.NET的工作目录通常与PowerShell的工作目录 * 不同 *(参见this answer)。
  • 虽然PowerShell惯用的Get-Content(没有-Raw)也可以工作,但不幸的是,它要慢得多,因为每一行读取都用ETS (Extended Type System)属性进行了修饰。
  • 根据GitHub issue #7537,通过-NoExtendedMember开关引入这种昂贵的装饰的 * 选择退出 * 已经亮起绿灯,但还没有人加强实现它(截至PowerShell 7.3.10,截至本文撰写时)。

[1]但是,如果集合值属性包含 * 不同类型的示例 *,则可能必须显示 * 所有 * 元素。

相关问题