Фильтровать большие файлы CSV - PullRequest
2 голосов
/ 23 октября 2019

У меня есть несколько больших файлов CSV (500 МБ +) с идентичными заголовками, и я хотел бы объединить их в консолидированный файл после фильтрации по типу машины = рабочие станции. Как отфильтровать с определенным заголовком столбца "machine_type" как "рабочие станции". Приведенный ниже код работает, но создает файл CSV со слишком большим количеством данных строк. Ценю помощь. Import-Csv дает мне исключение "System.OutofMemoryException".

$inputFolder = c:\change\imput
$outputFile  = 'C:\Change\filtered.csv'

$writer = New-Object IO.StreamWriter ($outputFile, $false)

Get-ChildItem $inputFolder -File | Where-Object {
$_.Extension -eq '.csv'
} | ForEach-Object {
  $reader = New-Object IO.StreamReader ($_.FullName)
  if (-not $headerWritten) {
    # copy header line to output file once
    $writer.WriteLine($reader.ReadLine())
    $headerWritten = $true
  } else {
    # discard header line
    $reader.ReadLine()
  }

  while ($reader.Peek() -ge 0) {
    $line   = $reader.ReadLine()
    $fields = $line -split ','
    #if ($line -match 'Workstation' ) {  
      $writer.WriteLine($line)
    #}
  }

  $reader.Close()
  $reader.Dispose()
}

$writer.Close()
$writer.Dispose()

Ответы [ 2 ]

1 голос
/ 23 октября 2019

Это должно работать без исключений OOM:

Get-ChildItem $inputFolder -File -Filter '*.csv' |
    ForEach-Object { Import-Csv $_.FullName } |
    Where-Object { $_.machine_type -eq 'workstations' } |
    Export-Csv $outputFile -NoType
0 голосов
/ 23 октября 2019

поправьте меня, если я ошибаюсь, но я предполагаю, что слово "Рабочая станция" также встречается в других столбцах, кроме workstation_type, так что оно также соответствует этим строкам? Для этого вы можете использовать более сложное регулярное выражение (используя группы захвата), см. Код ниже:

$inputFolder = 'c:\temp\csv'
$outputFile  = 'C:\temp\filtered.csv'

$headerWritten = $false
[regex] $csvPattern = '(?imx)^(?<name>\w+)(\s?,\s?)(?<machine_type>\w+)(\s?,\s?)(?<location>\w+)'

$writer = New-Object IO.StreamWriter ($outputFile, $false)

Get-ChildItem $inputFolder -File | Where-Object {
$_.Extension -eq '.csv'
} | ForEach-Object {
  $reader = New-Object IO.StreamReader ($_.FullName)
  if (-not $headerWritten) {
    # copy header line to output file once
    $writer.WriteLine($reader.ReadLine())
    $headerWritten = $true
  } else {
    # discard header line
    $reader.ReadLine()
  }

  while ($reader.Peek() -ge 0) {
    $line   = $reader.ReadLine()

    if ($csvPattern.Match($line).Groups.Item('machine_type').value -eq 'WorkStation' ) {  
        if ($line -match 'Workstation' ){
      $writer.WriteLine($line)
    }
  }

  $reader.Close()
  $reader.Dispose()
}

$writer.Close()
$writer.Dispose()
...