我有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
答案 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。这里的策略是:
strDir
变量(表示包含所有CSV的目录的字符串)希望这有帮助!
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