#powershell
#csv #powershell
Вопрос:
Мне нужно удалить несколько столбцов из файла CSV без импорта файла CSV в Powershell. Ниже приведен пример моего входного CSV и, как я надеюсь, может выглядеть выходной CSV.
Input.csv
A,1,2,3,4,5
B,6,7,8,9,10
C,11,12,13,14,15
D,15,16,17,18,19,20
Idealoutput.csv
A, 3,5
B, 8,10
C, 13,15
D, 17,20
Я пытался сделать это с помощью следующего кода, но он выдает мне множество ошибок и говорит, что я не могу использовать метод «Удалить» таким образом (что я делал в прошлом)…Есть идеи?
$Workbook1 = $Excel.Workbooks.open($file.FullName)
$header = $Workbook1.ActiveSheet.Range("A1:A68").EntireRow
$unneededcolumns1 = $Workbook1.ActiveSheet.Range("A1:O1").EntireColumn
$unneededcolumns2 = $Workbook1.ActiveSheet.Range("B1:K1").EntireColumn
$unneededcolumns3 = $Workbook1.ActiveSheet.Range("F1:I1").EntireColumn
$unneededcolumns4 = $Workbook1.ActiveSheet.Range("G1:I1").EntireColumn
$unneededcolumns5 = $Workbook1.ActiveSheet.Range("H1:O1").EntireColumn
$unneededcolumns6 = $Workbook1.ActiveSheet.Range("J1:AL1").EntireColumn
$unneededcolumns7 = $Workbook1.ActiveSheet.Range("K1").EntireColumn
$unneededcolumns8 = $Workbook1.ActiveSheet.Range("L1:AK1").EntireColumn
$unneededcolumns9 = $Workbook1.ActiveSheet.Range("F1:I1").EntireColumn
$unneededcolumns10 = $Workbook1.ActiveSheet.Range("M1:AB1").EntireColumn
$unneededcolumns11 = $Workbook1.ActiveSheet.Range("N1:X1").EntireColumn
$unneededcolumns12 = $Workbook1.ActiveSheet.Range("O1:BA1").EntireColumn
$unneededcolumns13 = $Workbook1.ActiveSheet.Range("P1:U1").EntireColumn
$header.Delete()
$unneededcolumns1.Delete()
$unneededcolumns2.Delete()
$unneededcolumns3.Delete()
$unneededcolumns4.Delete()
$unneededcolumns5.Delete()
$unneededcolumns6.Delete()
$unneededcolumns7.Delete()
$unneededcolumns8.Delete()
$unneededcolumns9.Delete()
$unneededcolumns10.Delete()
$unneededcolumns11.Delete()
$unneededcolumns12.Delete()
$unneededcolumns13.Delete()
$Workbook1.SaveAs("\output.csv")
Комментарии:
1. Почему вы не можете импортировать его в PowerShell? Это было бы очень просто сделать.
2. Я не уверен, что вы выбираете правильные диапазоны здесь… Вы понимаете, что
$Workbook1.ActiveSheet.Range("A1:A68").EntireRow.Delete()
это эффективно удалит содержимое всех ячеек в первых 68 первых строках вашего рабочего листа, верно?
Ответ №1:
Я все равно собираюсь добавить это, так как надеюсь убедить вас, насколько легко будет избежать использования Excel.
$source = "c:tempfile.csv"
$destination = "C:tempnewfile.csv"
(Import-CSV $source -Header 1,2,3,4,5,6 |
Select "1","4","6" |
ConvertTo-Csv -NoTypeInformation |
Select-Object -Skip 1) -replace '"' | Set-Content $destination
Мы присваиваем объекту произвольные заголовки, и таким образом мы можем вызывать 1-й, 4-й и 6-й столбцы по позиции. После экспорта файл будет иметь следующее содержимое, которое соответствует тому, что, я думаю, вы хотите, а не тому, что у вас было в вопросе. В вашей последней строке было добавлено дополнительное значение (20), которое я не знаю, было ли это специально или нет.
A,3,5
B,8,10
C,13,15
D,17,19
Если это невозможно, мне действительно интересно, почему.
Подход Excel
Хорошо, файл огромен, поэтому Import-CSV не является жизнеспособным вариантом. Следуя вашей идее Excel, я придумал это. Что он будет делать, так это брать индексы столбцов и удалять любой столбец, которого нет в этих индексах.
Подождите, что вы скажете?… это не сработает, поскольку индексы столбцов меняются при удалении столбцов. Используя индексы, которые мы хотим сохранить, мы получаем обратное удаление на основе UsedRows
листа. Затем мы берем каждый из этих столбцов для удаления и удаляем значение, равное позиции массива. Причина в том, что когда столбец фактически удаляется, следующее значение уже скорректировано с учетом сдвига.
$file = "c:tempfile.csv"
$ColumnsToKeep = 1,4,6
# Create the com object
$excel = New-Object -comobject Excel.Application
$excel.DisplayAlerts = $False
$excel.visible = $False
# Open the CSV File
$workbook = $excel.Workbooks.Open($file)
$sheet = $workbook.Sheets.Item(1)
# Determine the number of rows in use
$maxColumns = $sheet.UsedRange.Columns.Count
$ColumnsToRemove = Compare-Object $ColumnsToKeep (1..$maxColumns) | Where-Object{$_.SideIndicator -eq "=>"} | Select-Object -ExpandProperty InputObject
0..($ColumnsToRemove.Count - 1) | %{$ColumnsToRemove[$_] = $ColumnsToRemove[$_] - $_}
$ColumnsToRemove | ForEach-Object{
[void]$sheet.Cells.Item(1,$_).EntireColumn.Delete()
}
# Save the edited file
$workbook.SaveAs("C:tempnewfile.csv", 6)
# Close excel and release the com object.
$workbook.Close($true)
$excel.Quit()
[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
Remove-Variable excel
У меня возникли проблемы с тем, что Excel оставался открытым даже после прочтения «правильного» способа сделать это. Важна внутренняя логика. Не забудьте изменить пути по мере необходимости.
Комментарии:
1. Прошу прощения за то, что не указал на это в своем первоначальном сообщении. Я не могу импортировать-CSV, потому что файлы слишком большие, и Powershell занимает много времени, очень много времени для обработки каждого.
2. @CarlosSousa ах, хорошо…. Однако Excel все еще не нужен . Можем ли мы предположить, что данные не содержат запятых? Также вы читали комментарий Матиаса
3. @CarlosSousa Я обновил код, чтобы включить решение на основе Excel. Попробуйте это и дайте мне знать, если это сработает.
4. большое спасибо. Это действительно работает. Мне любопытно, есть ли лучший способ справиться с этим? т. Е. За пределами Excel? подход, не основанный на Excel, может быть более эффективным, верно? Есть предложения?
5. Вы можете использовать streamreader или get-content с некоторыми переключателями с комбинированной логикой моего первого ответа. Взгляните на rkeithhill.wordpress.com/2007/06/17 /…
Ответ №2:
Вот лучший подход, который я использую, но он не самый эффективный для больших файлов. Оба были протестированы на файлах объемом 1 ГБ.
Powershell:
Import-Csv '.inputfile.csv'
| select ColumnName1,ColumnName2,ColumnName3
| Export-Csv -Path .outputfile.csv -NoTypeInformation
Если вы хотите избавиться от этих надоедливых кавычек, добавляемых инструментом, обновитесь до Powershell 7.
Powershell 7 :
Import-Csv '.inputfile.csv'
| select ColumnName1,ColumnName2,ColumnName3
| Export-Csv -Path .outputfile.csv -NoTypeInformation -UseQuotes Never