解析大型文本文件(1 GB / 130万行),并有效地将记录拆分为文件名

时间:2019-04-25 12:09:35

标签: powershell

我有一个1 GB的文本文件,我的PowerShell代码需要5个小时才能根据记录名称进行拆分。

"STD|AAAA|X|dummy" "dummy"
"STD|BBBB|X|dummy" "dummy"
"STD|CCCC|X|dummy" "dummy"
"STD|AAAA|X|dummy" "dummy"

预期结果是创建3个文本文件(AAAA.txt,BBBB.txt,CCCC.txt),其中也包含匹配的行。

$data = get-content "$input_path"

foreach ($line in $data) {
    $matches  = [regex]::Match($line, 'STD\|(?<TheFilename>[^\|`"]+)[\|`"]+')
    $FirstLvl = $matches.Groups['TheFilename']

    if ($FirstLvl.Value -ne "") {
        $FullPath = Join-Path $ParentPath -ChildPath $FirstLvl.Value
        $line | Out-File -FilePath "$FullPath" -Append
    }
}

1 个答案:

答案 0 :(得分:2)

首先,不要将整个输入文件读入内存。请改用管道。并在管道处拆分行以提取文件基名,而不是使用正则表达式匹配。另外,实际上是否存在没有基本名称字段的行?否则,检查$FirstLvl是否为空会浪费资源。

Get-Content $input_path | ForEach-Object {
    $FirstLvl = $_.Split('|')[1]
    $_ | Add-Content "${ParentPath}\${FirstLvl}.txt"
}

如果您需要比.NET方法更好的性能。

$reader  = [IO.StreamReader]$input_path
$writers = @{}

while ($reader.Peek() -ge 0) {
    $line     = $reader.ReadLine()
    $FirstLvl = $line.Split('|')[1]

    if (-not $writers.Contains($FirstLvl)) {
        $writers[$FirstLvl] = [IO.StreamWriter]"${ParentPath}\${FirstLvl}.txt"
    }

    $writers[$FirstLvl].WriteLine($line)
}

$reader.Close()
$reader.Dispose()
foreach ($key in $writers.Keys) {
    $writers[$key].Close()
    $writers[$key].Dispose()
}

通过在哈希表中为每个输出文件存储单独的编写器,您不必重复重复打开输出文件。