2015-01-05 3 views
2

У меня есть набор файлов 500 csv. Каждый файл имеет четыре столбца и переменное количество строк.Объединить много файлов 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

Вы женаты на powershell для выполнения этой задачи или можете использовать Excel? –

+0

Вы упоминаете CSV в какой-то момент, но вы называете их листами excel. Все ли они CSV? Или они действительно листы Excel? – EBGreen

+0

Все CSV. Простите за это. – Powershel

ответ

4

Если все файлы CSV находятся в одной папке, то:

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

Расщипление:

  • $res = @() - создать массив с именем $ рес, который будет содержать все данные. Это строго не требуется. Вы можете сделать это таким образом, чтобы добавить к результату файл напрямую.

  • ls *.csv | - Найти все CSV-файлы в папке и передать их следующей команде.

  • %{$temp = Import-CSV $_; $res += $temp} - Возьмите каждый из этих файлов, импортируйте данные CSV в переменную держателя под названием $temp. Добавьте содержимое переменной $temp к переменной коллектора $res. Опять же, нет необходимости использовать промежуточную переменную $tamp, я просто нахожу ее более понятной для этого.

  • $res | Export-CSV .\ALLINFO.csv -NoTypeInformation - Теперь, когда данные из всех файлов находятся в $res, экспортируйте $res в новый файл.

1

В вашем случае sort name является необязательным в зависимости от того, следует ли слияние перегруппировать содержимое (очевидно, вы можете sort на другой параметр, а). Такое же условие, как и выше, - все CSV-файлы в одном каталоге.

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

С ScriptingGuy.

+0

Оператор задает несколько файлов. Не только один – Matt

+0

@Matt эта команда принимает * ввод a la 'c: \ *. Csv' и может обращаться к нескольким файлам. – meatspace

+0

Я знаю об этом. Оп не может быть. Поскольку в вопросе было задано несколько вопросов о нескольких файлах, ответ должен также отвечать на несколько файлов. – Matt

1

Вот очень прокомментированное решение, которое использует VBA в Excel для объединения CSV. Стратегия здесь такова:

  1. Установите ссылки авансовый, самое главное переменной strDir (который является строкой, представляющей каталог, который содержит все тома CSV)
  2. Loop через каталог
  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 
4

Если файлы большие, вы можете объединить их в текстовые документы. Это намного быстрее, чем импорт csv-объектов, но для этого требуются свойства и порядок их размещения во всех файлах.Пример:

$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() и т.д., но я пропустил, что сейчас, как это сложнее/трудно читать.

UPDATE: Добавлено альтернативное решение, которое сохраняет часть выходного файла для части, как предложил 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 
+1

Сбор всей информации в переменной может стать проблемой, особенно с большими файлами. Я бы сделал «Get-Content ... -TotalCount 1 | Set-Content Output.csv' и '$ files | ForEach-Object {...} | Add-Content Output.csv' вместо этого. –

+0

Правда, ответьте на обновления. Я еще не работал с файлами, достаточно большими, чтобы создать проблему, но, сохраняя одну часть за один раз, как вы предлагали, вы были бы в безопасности. Моя попытка была скорее «доказательством концепции». В реальном сценарии я бы, вероятно, также использовал '[System.IO.File]'. :) –

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