В Powershell Import CSV разбить на несколько файлов каждые 10 строк - PullRequest
1 голос
/ 12 октября 2019

Я новичок в кодировании PowerShell, и я пытаюсь импортировать файлы CSV с неизвестным количеством строк, а затем разбивать их каждые 10 строк на новый файл CSV.

Примересли я введу файл CSV из 97 строк, я ожидаю, что 9 файлов по 10 строк и 1 файл из 7 строк.

я попробовал следующее, Hostlist.csv содержит 35 имен хостов, я получаю 3 файла,в первом файле отсутствует первый хост в списке, а 4-го файла с оставшимся хостом нет.

$Hostlist = Get-Content '.\Hostlist.csv'
$BatchID = Get-Random
New-Item -ItemType Directory -Force -Path .\$BatchID
$MaxBatch = 10
$line = 0
$i = 0
$File = 0

While ($line -lt $Hostlist.Length) {

    if ($i -gt $MaxBatch) {
        $Start = $line - $MaxBatch
        $File++
        $Hostlist[$Start..($line-1)] | Out-File ".\$BatchID\Batch$File.csv" -Append -force
        $i = 0
    }
    $i++;
    $line++
}

Ответы [ 2 ]

1 голос
/ 12 октября 2019

В качестве отступления:

  • Если ваш входной файл является CSV-файлом и вы хотите, чтобы ваши выходные файлы тоже были CSV-файлами, вам нужно будет написать строку заголовка для каждого.

  • Ваш код не пытается этого сделать, поэтому я предполагаю, что вы просто имеете дело с текстовыми файлами, ориентированными на строки, несмотря на расширение имени файла .csv.

в первом файле отсутствует первый хост

Так как ваше условие для обработки пакета равно $i -gt $MaxBatch, $i и $lineи 11 при первом входе в блок if, и поэтому $Start = $line - $MaxBatch равен 1, то есть строка секунда , учитывая, что $Start используется как массив на основе 0index.

нет 4-го файла с оставшимся хостом.

Так как вы обрабатываете пакет, только если $i -gt $MaxBatch, входной файл, число строк которого неделится на $MaxBatch и всегда будет пропускать свою последнюю партию, потому что последняя, ​​неполная партия никогда не удовлетворяет условию if.


Я предлагаю упростить ваш код путем вычисления количества пакетов и циклического выполнения пакета для пакета, как показано в следующем упрощенном примере, который разбивает 10-строчный ввод на пакеты по 3:

# Simulate the list of hosts
$HostList = 1..10 -replace '^', 'host$&' # 'host1', 'host2', ...

# Batch size
$MaxBatch = 3

foreach ($batch in 1..[math]::Ceiling($Hostlist.Count / $MaxBatch)) {
  write-verbose -Verbose "File index (batch number): $batch"
  $startNdx = ($batch-1) * $MaxBatch
  $Hostlist[$startNdx..($startNdx + $MaxBatch - 1)]
}

Обратите внимание, как использование [math]::Ceiling() в подсчете количества партий $Hostlist.Count / $MaxBatch гарантирует, что неполная партия в конце также обрабатывается.

Если у вас не действует Set-StrictMode -Version 3 или выше, этодопустимо превышать верхнюю границу массива в выражении диапазона .., используемом для нарезки массива в конечном, неполном пакете - PowerShell просто игнорирует индексы за пределами верхней границы.

Вышеприведенные значения:

VERBOSE: File index (batch number): 1
host1
host2
host3
VERBOSE: File index (batch number): 2
host4
host5
host6
VERBOSE: File index (batch number): 3
host7
host8
host9
VERBOSE: File index (batch number): 4
host10
0 голосов
/ 12 октября 2019

ваш код не создаст правильный файл CSV, так как вы не обрабатываете информацию заголовка и не используете Import-CSV, чтобы позволить вам иметь дело с объектами, которые естественно экспортируются как CSV. поэтому я пошел с кодом, написанным для другого человека.

$SourceDir = $env:TEMP
$SourceFile = 'Source.csv'
$FullSourceFile = Join-Path -Path $SourceDir -ChildPath $SourceFile

$BatchSize = 4

$OutputDir = $env:TEMP
$OutputFile = 'Output.csv'
$FullOutputFile = Join-Path -Path $OutputDir -ChildPath $OutputFile

#$InCSV = Import-Csv -Path $FullSourceFile

#region - fake reading in CSV
# fake reading in a CSV file
#    in real life, use Import-CSV above
$InCSV = @'
Col_1,Col_2,Col_3,Col_4
row-1-1, row-1-2, row-1-3, row-1-4
row-2-1, row-2-2, row-2-3, row-2-4
row-3-1, row-3-2, row-3-3, row-3-4
row-4-1, row-4-2, row-4-3, row-4-4
row-5-1, row-5-2, row-5-3, row-5-4
row-6-1, row-6-2, row-6-3, row-6-4
row-7-1, row-7-2, row-7-3, row-7-4
row-8-1, row-8-2, row-8-3, row-8-4
row-9-1, row-9-2, row-9-3, row-9-4
row-10-1, row-10-2, row-10-3, row-10-4
'@ | ConvertFrom-Csv
#endregion - fake reading in CSV

$Count = 0
$Remaining = $InCSV.Count
$Batch = [System.Collections.Generic.List[PSObject]]::new()
foreach ($IC_Item in $InCSV)
    {
    $Count ++
    $Ready = $False

    $Batch.Add($IC_Item)

    if ($Count -eq $BatchSize)
        {
        $Ready = $True
        $Count = 0
        }

    $Remaining --
    if ($Remaining -eq 0)
        {
        $Ready = $True
        }

    if ($Ready)
        {
        $TimeStamp = Get-Date -Format 'yyyy-MM-dd__HH-mm-ss__fff'
        $NewFullOutputFile = $FullOutputFile.Replace('.csv', "$TimeStamp.csv")

        $Batch | 
            Export-Csv -LiteralPath $NewFullOutputFile -NoTypeInformation

        $Batch.Clear()
        }
    }

экран не выводится. вот содержимое первого CSV ...

"Col_1","Col_2","Col_3","Col_4"
"row-1-1","row-1-2","row-1-3","row-1-4"
"row-2-1","row-2-2","row-2-3","row-2-4"
"row-3-1","row-3-2","row-3-3","row-3-4"
"row-4-1","row-4-2","row-4-3","row-4-4"

содержание последнего CSV ...

"Col_1","Col_2","Col_3","Col_4"
"row-9-1","row-9-2","row-9-3","row-9-4"
"row-10-1","row-10-2","row-10-3","row-10-4"
...