2016-10-23 11 views
0

私はCampaignNamesとIDを含むファイルを持っています。 2つのフィールドはパイプ|で区切られています。 IDはスペースで区切られています。私はIDを含むファイル(胸元þ区切られた)のすべての行を見つけ、その行を名前ごとに別々のファイルに出力したいと考えています。このファイルのサイズは通常4〜7 GBです。別のファイルで文字列を検索し、特定の列を出力します。

campaigns.txt

Name|NameID 
FirstName|123 212 445 39 
SecondName|313 939 
ThirdName|219

データIDファイル:

DateþIDþCode 
10-22-14þ123þAbc 
10-24-16þ212þPow 
09-18-15þ219

だから私は3つのファイルが作成されたいです。 FirstName.txtには2行が含まれています。 SecondName.txtには0行が含まれます。 ThirdName.txtには1行が含まれます。

私はさまざまなソースからいくつかのコードを一緒に冠し、これを思いついた。しかし、データファイルを何度も読み込むよりも良い方法があるのだろうかと思います。そこにはどんな考えがありますか?

$campaigns = Import-Csv "campaigns.txt" -Delimiter "|" 
$datafile = "5282_10-19-2016" 
$encoding = [Text.Encoding]::GetEncoding('iso-8859-1') 

echo "Starting.." 
Get-Date -Format g 

foreach ($campaign in $campaigns) { 
    $campaignname = $campaign.CampaignName 
    $campaignids = $campaign.CampaignID.split(" ") 
    echo "Looking for $campaignname - $campaignids" 
    $writer = New-Object System.IO.StreamWriter($campaignname + "_filtered.txt") 
    foreach ($campaignid in $campaignids) { 
     $datareader = New-Object System.IO.StreamReader($datafile, $encoding) 
     while ($dataline = $datareader.ReadLine()) { 
      if ($dataline -match $campaignid) { 
       $data = $dataline.Split("þ") 
       $writer.WriteLine('{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}', $data[0], $data[3], $data[5], $data[8], $data[12], $data[14], $data[19], $data[20]) 
      } 
     } 
    } 
    $writer.Close() 
} 

echo "Done!" 
Get-Date -Format g 

答えて

1

巨大なデータファイルを1回だけ処理します。
campaign.txtから作成したハッシュテーブルからキャンペーン名を選択します。
多くのStreamWriterに多くのキャンペーン(たとえば、1000未満)が書き込まれないと仮定します。

$campaignByID = @{} 
foreach ($c in (Import-Csv 'campaigns.txt' -Delimiter '|')) { 
    foreach ($id in ($c.CampaignID -split ' ')) { 
     $campaignByID[$id] = $c.CampaignName 
    } 
} 

$campaignWriters = @{} 
$datareader = New-Object IO.StreamReader($datafile, $encoding) 
while (!$datareader.EndOfStream) { 
    $data = $datareader.ReadLine().Split('þ') 
    $campaignName = $campaignByID[$data[1]] 
    if ($campaignName) { 
     $writer = $campaignWriters[$campaignName] 
     if (!$writer) { 
      $writer = $campaignWriters[$campaignName] = 
       New-Object IO.StreamWriter($campaignName + '_filtered.txt') 
     } 
     $writer.WriteLine(($data[0,3,5,8,12,14,19,20] -join '|')) 
    } 
} 

$datareader.Close() 
foreach ($writer in $campaignWriters.Values) { 
    $writer.Close() 
} 

は、例えば、それを1秒ごとに行う日時変数を使用して、 $datareader.BaseStream.Position/$datareader.BaseStream.Length * 100に基づく進捗使用 Write-Progressを表示するには、それが処理を遅くますので、すべてのデータ・ファイルの行のためにそれをしない:それを更新します秒が経過して進行状況が表示されます。

+0

うわー、これは時間の4GBのファイルのための20分の処理時間を降ろしました。ありがとうございました! – Esuriency

-1

これを試してみてください;)

$campaigns=import-csv C:\temp\campaigns.txt -Delimiter "|" 
    $datafile=import-csv C:\temp\5282_10-19-2016.txt -Delimiter "þ" -Encoding Default 
    $DirResult="C:\temp\root" 

    $campaigns | %{ foreach ($item in ($_.NameID.Split(" "))) {New-Object PSObject -Property @{ Name=$_.Name ; ValID=$item} } } | %{ $datafile | where id -eq $_.ValID | export-csv -Append -Delimiter "|" -Path ("$dirresult\" + $_.ValID + "_filtered.txt") -NoTypeInformation } 
+1

実際、これを試してはいけません。 'Import-Csv'は遅いですが、数ギガバイトのデータファイルをメモリに読み込むのは悪いアドバイスです。システムは、スワッピングを開始するため、クロールに最も遅くなる可能性があります。 –

関連する問題