将多个 csv 文件合并为一个的 Powershell 脚本

Powershell script to combine multiple csv files to single one

我在 C:\temp 中有 3 个 csv 文件。尝试将所有 3 个 csv 文件合并为单个文件。 F1.csvF2.csvF3.csv [都具有唯一的 headers 和不同的行数和列数]。以下是文件中的示例内容。

F1.csv

F1C1    F1C2
ABC     123

F2.csv

F2C1    F2C2
DEF     456
GHI     789
JKL     101112

F3.csv

F3C1    
MNO    
PQR

我希望结果 csv 文件 FR.csv 如下所示 FR.csv

F1C1 F1C2 F2C1 F2C2    F3C1
ABC  123  DEF  456     MNO
          GHI  789     PQR
          JKL  101112  

我试过 运行 下面的脚本,但是 FR.csv 在单列中给出了输出。

Get-Content C:\temp\*csv | Add-Content C:\temp\FinalResult.csv

以下解决方案假定 Get-ChildItem *.csv 按所需顺序枚举要合并的文件(适用于输入文件 F1.csvF2.csvF3.csv当前目录)。


Plain-text解决方案,使用.NET API,System.IO.StreamReaderand System.IO.StreamWriter

此解决方案比下面的 OO 解决方案执行得更好,但后者为您提供更大的灵活性。没有 Unicode BOM 的输入文件被假定为 UTF-8 编码,输出保存到当前目录中名为 FR.csv 的 BOM-less UTF8 文件。 (如果需要,所使用的 API 允许您指定不同的编码)。

$outFile = 'FR.csv'
# IMPORTANT: Always use *full* paths with .NET APIs.
# Writer for the output file.
$writer = [System.IO.StreamWriter] (Join-Path $Pwd.ProviderPath $outFile)
# Readers for all input files.
$readers = [System.IO.StreamReader[]] (Get-ChildItem *.csv -Exclude $outFile).FullName

# Read all files in batches of corresponding lines, join the 
# lines of each batch with ",", and save to the output file.
$isHeader = $true
while ($readers.EndOfStream -contains $false) {
  if ($isHeader) {
    $headerLines = $readers.ReadLine()
    $colCounts = $headerLines.ForEach({ ($_ -split ',').Count })
    $writer.WriteLine($headerLines -join ',')
    $isHeader = $false
  } else {
    $i = 0
    $lines = $readers.ForEach({
      if ($line = $_.ReadLine()) { $line }
      else                       { ',' * ($colCounts[$i] - 1) }
      ++$i
    })
    $writer.WriteLine($lines -join ',')
  }
}

$writer.Close()
$readers.Close() 

OO解决方案,使用Import-Csv and ConvertTo-Csv / Export-Csv:

# Read all CSV files into an array of object arrays.
$objectsPerCsv = 
  Get-ChildItem *.csv -Exclude FR.csv | 
    ForEach-Object { 
      , @(Import-Csv $_.FullName)
    }

# Determine the max. row count.
$maxCount = [Linq.Enumerable]::Max($objectsPerCsv.ForEach('Count'))

# Get all column names per CSV.
$colNamesPerCsv = $objectsPerCsv.ForEach({ , $_[0].psobject.Properties.Name })

0..($maxCount-1) | ForEach-Object {
  $combinedProps = [ordered] @{}
  $row = $_; $col = 0
  $objectsPerCsv.ForEach({
    if ($object = $_[$row]) { 
      foreach ($prop in $object.psobject.Properties) {
        $combinedProps.Add($prop.Name, $prop.Value)
      }    
    }
    else { 
      foreach ($colName in $colNamesPerCsv[$col]) {
        $combinedProps.Add($colName, $null)
      }
    }
    ++$col
  })
  [pscustomobject] $combinedProps
} | ConvertTo-Csv 

ConvertTo-Csv替换为Export-Csv以将数据导出到文件;根据需要使用 -NoTypeInformation 参数和 -Encoding;例如
... | Export-Csv -NoTypeInformation -Encoding utf8 Merged.csv