2016-10-23 2 views
0

У меня есть файл, содержащий имена и идентификаторы Campaign. Два поля разделены трубой |. Идентификаторы разделяются пробелом. Я хочу найти все строки в файле (thorpe þ с разделителями), которые содержат идентификаторы, и выводят эти строки в отдельные файлы для имени. Этот файл обычно составляет 4-7 ГБ, иногда больше.Найти строки в одном файле в другом и вывести определенные столбцы

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

Обработайте огромный файл данных только один раз.
Выберите имена кампаний из хеш-таблицы, построенной из файла campaign.txt.
Предполагая, что не так много кампаний (скажем, менее 1000) пишут столько же StreamWriters.

$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() 
} 

Для отображения использования прогресса Write-Progress основанный на $datareader.BaseStream.Position/$datareader.BaseStream.Length * 100, но не делают это для каждого файла данных линии, потому что это будет замедлять обработку, делать это 1 раз в секунду, например, используя переменную типа DateTime: обновить когда прошло второе и отобразится прогресс.

+0

Wow это снесло время обработки от одного часа до 20 минут для файла 4 Гб. Спасибо! – 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

Собственно, не пробуйте это. «Импорт-Csv» работает медленно, но чтение файла данных объемом в несколько гигабайт - это просто плохие советы. Система, скорее всего, замедлит сканирование, потому что она начнет свопинг. –

Смежные вопросы