【问题标题】:What is the most efficient way to replace all \ with \\, within a huge JSON File?在一个巨大的 JSON 文件中,用 \\ 替换所有 \ 的最有效方法是什么?
【发布时间】:2020-05-08 00:30:28
【问题描述】:

我必须在一个巨大的 JSON 行文件中将所有出现的 \ 替换为 \\。我想使用 Powershell,但也可能有其他选择。 源文件有 4.000.000 行,大约 6GB。

我使用的 Powershell 脚本花费了太多时间,我让它运行了 2 个小时,还没有完成。半小时的表演是可以接受的。

$Importfile = "C:\file.jsonl"
$Exportfile = "C:\file2.jsonl"

(Get-Content -Path $Importfile) -replace "[\\]", "\\" | Set-Content -Path $Exportfile

【问题讨论】:

  • 我将其添加到问题中。

标签: json powershell optimization


【解决方案1】:

如果替换只是将单个反斜杠转换为双反斜杠,则可以逐行处理文件。

使用 StringBuilder 将数据放入内存缓冲区,该缓冲区不时刷新到磁盘上。像这样,

$src = "c:\path\MyBigFile.json"
$dst = "c:\path\MyOtherFile.json"
$sb = New-Object Text.StringBuilder
$reader = [IO.File]::OpenText($src)
$i = 0
$MaxRows = 10000

while($null -ne ($line = $reader.ReadLine())) {
    # Replace slashes
    $line = $line.replace('\', '\\') 
    # ' markdown coloring is confused by backslash-apostrophe
    # so here is an extra one just for looks

    [void]$sb.AppendLine($line)
    ++$i

    # Write builder contents into file every now and then
    if($i -ge $MaxRows) {
        add-content $dst $sb.ToString() -NoNewline
        [void]$sb.Clear()
        $i = 0
    }
}
# Flush the builder after the while loop if there's data
if($sb.Length -gt 0) {
    add-content $dst $sb.ToString() -NoNewline
}
$reader.close()

【讨论】:

  • 它非常快,只是它在字符串生成器的末尾放了一个空行。导致文件中每 10000 (MaxRows) 行出现一个空行。它尝试解决它除了在 CSV 文件准备好时删除它们之外没有成功,你有没有办法以有效的方式删除空行?
  • @MartijnOlthuis 现在有-NoNewline 参数应该可以解决额外的换行问题。
【解决方案2】:

Get-Content cmdlet 使用-ReadCount 参数(并将其设置为0)。

-ReadCount

指定多少行内容通过管道发送 时间。默认值为 1。值 0(零)发送所有 一次内容。

这个参数不会改变显示的内容,但是会 影响显示内容所需的时间。作为价值 ReadCount 增加,返回第一行所需的时间 增加,但操作的总时间减少。这个可以 对大件物品产生明显的影响。

示例(文件 cca 20MB 的运行速度提高了 cca 17 倍):

$file = 'D:\bat\files\FileTreeLista.txt'
(Measure-Command { 
    $xType = (Get-Content -Path $file             ) -replace "[\\]", "\\"
}).TotalSeconds, $xType.Count -join ', '
(Measure-Command {
    $yType = (Get-Content -Path $file -ReadCount 0) -replace "[\\]", "\\"
}).TotalSeconds, $yType.Count -join ', '
Get-Item $file | Select-Object FullName, Length
13,3288848, 338070
 0,7557814, 338070

FullName                         Length
--------                         ------
D:\bat\files\FileTreeLista.txt 20723656

【讨论】:

    【解决方案3】:

    根据您之前的问题How can I optimize this Powershell script, converting JSON to CSV?。您应该尝试为此使用 PopwerShell 管道,尤其是当它涉及大型输入和输出文件时。
    关键是您不应该专注于解决方案的单个部分来确定性能,因为这通常会留下错误的印象,因为 完整 (PowerShell) 管道解决方案的性能应该优于其部分的总和。此外,它还节省了大量内存,结果是精简的 PowerShell 语法...
    在您的特定情况下,如果设置正确,CPU 将替换斜杠,重建 json 字符串并将其转换为对象,同时硬盘正忙于读取和写入数据...

    使用ConvertFrom-JsonLines cmdlet 将斜杠替换到 PowerShell 管道中:

    Get-Content .\file.jsonl | ForEach-Object { $_.replace('\', '\\') } |
    ConvertFrom-JsonLines | ForEach-Object { $_.events.items } |
    Export-Csv -Path $Exportfile -NoTypeInformation -Encoding UTF8
    

    【讨论】:

      猜你喜欢
      • 2018-12-19
      • 2021-08-30
      • 1970-01-01
      • 2021-08-15
      • 2015-01-20
      • 1970-01-01
      • 2020-01-15
      • 1970-01-01
      • 2015-08-06
      相关资源
      最近更新 更多