2016-12-02 21 views
0

以下のpowershellスクリプトを使用して、1つの17 MBテキストファイルを読み込んで処理しています。入力ファイルには、約200,000行と12個の列が含まれています。現在、スクリプトは入力ファイルを処理するのにほぼ1時間かかります。どのように処理時間を最適化するには?PowerShellを使用したテキストファイルの処理 - パフォーマンスの問題

スクリプト:私はここで何かが欠けていない限り

$fields = Get-Content Temp.txt 
$results = @() 
foreach($i in $fields) 
{ 
    $field = $i -split '\t' -replace '^\s*|\s*$' 
    $field1 = $field[0] 
    $field2 = $field[1] 
    $field3 = $field[2] 
    $field4 = $field[3] 
    $field5 = $field[4] 
    $field6 = $field[5] 
    $field7 = $field[6] 
    $field8 = $field[7] 
    $field9 = $field[8] 
    $field10 = $field[9] 
    $field11 = $field[10] 
    $field12 = $field[11] 

    if ($field1 -eq "4803" -and $field[2].substring(0,2) -eq "60") 
    { 
     $field2 = "5000000" 
    } 
    else 
    { 
     $field2 = $field[1] 
    } 
    $details = @{  
       Column1 = $field1 
       Column2 = $field2 
       Column3 = $field3 
       Column4 = $field4 
       Column5 = $field5 
       Column6 = $field6 
       Column7 = $field7 
       Column8 = $field8 
       Column9 = $field9 
       Column10 = $field10 
       Column11 = $field11 
       Column12 = $field12 
      } 
    $results += New-Object PSObject -Property $details 
    } 
$results | ForEach-Object { '{0} {1} ... {11}' -f $_.Column1,$_. Column1,... $_.Column12 } | Set-Content -path Temp.txt 
[Environment]::Exit(0) 
+0

よく、なぜこれをcsvとしてインポートしてみませんか? 'else'条件も冗長です。テストのために適切なファイルを提供できますか?すべての情報を何かに置き換えることができます – 4c74356b41

+0

私もimport-csvでテストしました。私は同じ問題に直面しています。それは1時間実行されています。しかし、10000レコードを処理するのに20秒しかかかりません。 – AravindhK

+0

[https://social.technet.microsoft.com/Forums/scriptcenter/en-US/c5bdc740-837a-43f6-97d5-b0f0d5bf22bc/](https://social.technet.microsoft.com/Forums/)の重複scriptcenter/ja-US/c5bdc740-837a-43f6-97d5-b0f0d5bf22bc /)。 StackOverflowは無料のコード再設計サービスでもありません。 –

答えて

2

目標は、タブ区切りのデータを取り込む別に基づいて1つのフィールドを変更して、CSVデータとして出力し、正しいことですか?もしそうなら、このワンライナーはずっと速く実行するべきです。

Import-Csv test.txt -Header @(1..12) -Delimiter `t | % {if(($($_.2) -eq "4803") -and($($_.3).substring(0,2) -eq "60")){$_.2 = "5000000"};$_} | export-csv test2.csv -NoTypeInformation 

これは、すべての奇妙な文字列解析を回避し、行がスクリプトの各行の新しい配列にあなたの配列全体をコピーしていることを

$results += New-Object PSObject -Property $details

で最大の問題を回避して、そのパフォーマンス上問題があります。変更の残りの部分はわずかに速くなります。

+0

単に '$ results'を' Arraylist'に変更すれば、パフォーマンスが大幅に向上するのだろうかと思います – 4c74356b41

+0

AFAIKそれはまだファイルの各行のコピーを必要とします(私はこれをテストしておらず、間違っている可能性があります)、$ results = * foreachループ*を設定してパフォーマンスを向上させ、$ results + = insideループは、すべてのものをw/oにコピーすることを割り当てますが、いくつかの行が問題を起こさないようにするためにはまだまだ多くのコードです。 –

+0

この提案の大きな利点の1つは、大きなファイル全体を一度に読み込むのではなく、データをパイプライン化することです。 – lit

0

これが私の場合は、ファイルがもっと大きくなる場合、Get-Contentを使用しないことを考え始めるでしょう。メモリ消費量が問題になり始め、Get-Contentを使用すると、すべてがメモリに格納されるためファイルが非常に大きくなった場合にはうまく拡張できません。オブジェクトとしてオブジェクトを表現しなければならないので(XML DOMよりもまだ小さいが、メモリに関係なく)、ファイルのサイズよりもメモリが増えることに注意してください。入力ファイルをループストリームリーダーを使用して

だから最初にすべての、あなたは、私がここでの例を持つことができます:https://stackoverflow.com/a/32337282/380016

あなたはまた、代わりに大きなオブジェクトをconcattingの、ストリームライターを使用して、出力ファイルを書き込むことができますあなたのように、あまりにもループして、最後にファイルに書き出します。

私の例のwhileループでは、必要に応じてそのまま文字列を分割して操作してから書き出すことができます。それを蓄積し、最後にすべてを行うのを待つ必要はありません。

このアプローチは高速であり、ほとんどメモリを使用する必要はありません。

関連する問題