合并许多CSV文件

时间:2015-01-05 16:48:21

标签: excel vba excel-vba powershell

我有500个csv文件。每个文件有四列和可变行数。

我想将所有这些csv合并到一个常用的工作表中。如果有人可以帮助我在PowerShell中执行此操作,那就太棒了。

Sample Data in Excel 1:

Name  Age  Marks  Class
A      15   100    5
B      20   88     6

Sample Data in Excel 2:
Name   Age  Marks  Class
C      11   99      2

Output :
Name   Age   Marks   Class
A      15    100      5
B      20     88      6
C      11     99      2

4 个答案:

答案 0 :(得分:4)

如果所有CSV文件都在一个文件夹中,则:

$res = @()
ls *.csv | %{
  $temp = Import-CSV $_
  $res += $temp
}
$res | Export-CSV .\ALLINFO.csv -NoTypeInformation

分解:

  • $res = @() - 创建一个名为$ res的数组,它将保存所有数据。这不是严格要求的。您可以通过直接附加到结果文件的方式来执行此操作。

  • ls *.csv | - 查找文件夹中的所有CSV文件并将其传递给下一个命令。

  • %{$temp = Import-CSV $_; $res += $temp} - 获取每个文件,将CSV数据导入名为$temp的持有人变量中。将$temp的内容添加到收集器变量$res。同样没有必要使用中间$tamp变量,我只是发现它更清楚。

  • $res | Export-CSV .\ALLINFO.csv -NoTypeInformation - 现在所有文件中的数据都在$res中,导出$res到新文件。

答案 1 :(得分:4)

如果文件很大,那么您可以将它们合并为文本文档。这比导入csv-objects要快得多,但它要求所有文件中的属性和它们放置的顺序相等。例如:

$files = Get-ChildItem "*.csv"
#Get header
$text = @(Get-Content -Path $files[0].FullName -TotalCount 1)

$files | ForEach-Object {
    #Get text but skip header
    $text += Get-Content -Path $_.FullName | Select-Object -Skip 1
}

#Save merged csv
$text | Set-Content Output.csv

Output.csv

Name;Age;Marks;Class
A;15;100;5
B;20;88;6
C;11;99;2

您可以通过将Get-Content替换为[System.IO.File]::ReadAllLines()等来进一步优化它,但我现在跳过它,因为它更复杂/难以阅读。

更新:添加了另一种解决方案,可以按照Ansgar的建议保存输出文件部分。

$outputfile = "Output.csv"

$files = Get-ChildItem "*.csv"

#Get header
Get-Content -Path $files[0].FullName -TotalCount 1 | Set-Content -Path $outputfile

$files | ForEach-Object {
    #Get text but skip header
    Get-Content -Path $_.FullName | Select-Object -Skip 1
} | Add-Content -Path $outputfile

答案 2 :(得分:1)

在您的情况下,sort name是可选的,具体取决于合并是否也应重新排序内容(显然,您也可以sort对其他参数进行重新排序)。与上述相同的规定 - 所有.csv文件都在一个目录中。

dir c:\directory_containing_your\*.csv | Import-Csv | sort name | Export-Csv -Path c:\output.csv -NoTypeInformation

来自ScriptingGuy

答案 3 :(得分:1)

这是一个评论很多的解决方案,它使用Excel中的VBA来组合CSV。这里的策略是:

  1. 预先设置参考,最重要的是strDir变量(表示包含所有CSV的目录的字符串)
  2. 遍历目录
  3. 打开每个CSV
  4. 从每个CSV中复制相应的内容
  5. 将内容粘贴到输出工作簿
  6. 重复循环,直到所有文件都被迭代
  7. 希望这有帮助!

    Option Explicit
    Public Sub CombineCSVsInFolder()
    
    Dim strFile As String, strDir As String
    Dim wbkSource As Workbook, wbkOutput As Workbook
    Dim wksSource As Worksheet, wksOutput As Worksheet
    Dim lngLastRowSource As Long, lngLastRowOutput As Long
    Dim rngSource As Range, rngOutput As Range
    Dim blnFirst As Boolean
    
    'Set references up-front
    strDir = "c:\stack\my_csvs\" '<~ edit this line with the CSV directory
    strFile = Dir(strDir)
    blnFirst = True
    Set wbkOutput = Workbooks.Add
    Set wksOutput = wbkOutput.ActiveSheet
    Application.ScreenUpdating = False
    
    'Loop through the CSV directory
    While (strFile <> "")
    
        'Assign source CSV files
        Set wbkSource = Workbooks.Open(strDir & strFile)
        Set wksSource = wbkSource.ActiveSheet
    
        'Assign boundaries of area to copy and output
        lngLastRowSource = LastRowNum(wksSource)
        lngLastRowOutput = LastRowNum(wksOutput)
        With wksOutput
            Set rngOutput = .Cells(lngLastRowOutput + 1, 1)
        End With
    
        'If this is the first time through, include headers, otherwise do not
        If blnFirst = False Then
            With wksSource
                Set rngSource = .Range(.Cells(2, 1), .Cells(lngLastRowSource, 4))
            End With
        'Special case for first iteration to correct source and output ranges
        Else
            With wksSource
                Set rngSource = .Range(.Cells(1, 1), .Cells(lngLastRowSource, 4))
            End With
            With wksOutput
                Set rngOutput = .Cells(1, 1)
            End With
            blnFirst = False
        End If
    
    
        'Execute copy, close source and repeat
        rngSource.Copy rngOutput
        wbkSource.Close
        strFile = Dir
    Wend
    
    'Turn screen updates back on
    Application.ScreenUpdating = True
    
    End Sub
    
    
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'INPUT       : Sheet, the worksheet we'll search to find the last row
    'OUTPUT      : Long, the last occupied row
    'SPECIAL CASE: if Sheet is empty, return 1
    Public Function LastRowNum(Sheet As Worksheet) As Long
        If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
            LastRowNum = Sheet.Cells.Find(What:="*", _
                            LookIn:=xlFormulas, _
                            SearchOrder:=xlByRows, _
                            SearchDirection:=xlPrevious).Row
        Else
            LastRowNum = 1
        End If
    End Function