Экспорт данных в CSV - Каждое возвращаемое значение или сбор данных в хеш-таблицу в первую очередь? - PullRequest
0 голосов
/ 12 июня 2018

Я создал несколько скриптов Powershell, которые фокусируются на сборе данных.Я написал несколько функций, которые в основном работают так:

  • Подключение к машине
  • Получение любых необходимых мне данных
  • Добавление данных в существующий csv-файл

Теперь export-csv используется в функциях напрямую.Так что нет никакого возвращаемого значения как такового.Поскольку я все еще изучаю Powershell, я наткнулся на хеш-таблицы и подумал, может быть, стоит изменить мои функции для сбора данных в хеш-таблицы вместо того, чтобы экспортировать все мои переменные, заполненные данными напрямую.

Я не знаючто является лучшей практикой здесь.Производительность не проблема, но я думаю, что итерация по сотням машин, открытие CSV, запись в него и затем закрытие его может быть не лучшим с точки зрения ввода / вывода.

В качестве альтернативы я могу представить, чтоХранение всех моих собранных данных в хеш-таблице (или нескольких хеш-таблицах) перед их выводом может вызвать проблемы с памятью.

Вы можете мне помочь?Какой лучший подход здесь?

1 Ответ

0 голосов
/ 12 июня 2018

Существует два распространенных подхода к таким вещам:

  • Используйте цикл foreach и соберите данные в переменную, затем экспортируйте эту переменную в CSV.

    $data = foreach ($server in (Get-Content 'input.txt')) {
         # do stuff here, then build a custom object from the results
         New-Object -Type PSObject -Property @{
             'ComputerName' = $server
             ...
         }
    }
    
    $data | Export-Csv 'output.csv' -NoType
    
  • Используйте цикл ForEach-Object, в котором вы читаете ввод из конвейера и передаете вывод в Export-Csv через конвейер.

    Get-Content 'input.txt' | ForEach-Object {
        # do stuff here, then build a custom object from the results
        New-Object -Type PSObject -Property @{
            'ComputerName' = $_
            ...
        }
    } | Export-Csv 'output.csv' -NoType
    

Первый подход обеспечивает лучшую производительность, но имеет недостаток, заключающийся в том, что все данные считываются в память (циклы foreach не могут записывать в конвейер).Если у вас есть большие объемы данных, которые могут привести к исчерпанию памяти.

Последний подход устойчив к истощению памяти, поскольку конвейер обычно обрабатывает один объект за раз.Общая обработка выполняется медленнее, чем цикл foreach.

Какой из этих двух подходов лучше всего подходит для данного сценария, зависит от фактических данных, которые вы обрабатываете.

Я бы не рекомендовалпомещая Export-Csv в вашу функцию обработки, по крайней мере, не делая ее необязательной.С одной стороны, это не очень хорошая практика с точки зрения производительности.При вызове функции в цикле файл должен быть открыт повторно.Лучше всего открыть его один раз и закрыть после того, как все данные записаны.Кроме того, вы получаете гибкость, отделяя обработку от вывода.Пусть ваша функция возвращает «сырые» данные, и вы можете делать с ними все, что вам нужно (запись в CSV, отображение пользователю, передача в другое приложение, ...).

Пусть ваша функция принимаетвход конвейера, например, такой:

function Invoke-Foo {
    [CmdletBinding()]
    Param(
        [Parameter(
            Position=0,
            Mandatory=$true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        $InputObject,
        ...
    )

    Begin {
        # initialize stuff here
    }

    Process {
        $InputObject | ForEach-Object {
            # do stuff here, then build a custom object from the results
            New-Object -Type PSObject -Property @{
                ...
            }
        }
    }

    End {
        # cleanup goes here
    }
}

, и вы можете использовать его в foreach петле

$data = foreach ($server in (Get-Content 'input.txt')) {
    Invoke-Foo $server
}

$data | Export-Csv 'output.csv' -NoType

, а также в конвейере:

Get-Content 'input.txt' | Invoke-Foo | Export-Csv 'output.csv' -NoType

Если по какой-то причине у вас должна быть возможность записывать данные в файл из функции, я бы, вероятно, изменил функцию следующим образом:

function Invoke-Foo {
    [CmdletBinding()]
    Param(
        ...
        [Parameter(Mandatory=$false)]
        [string]$Path,
        [Parameter(Mandatory=$false)]
        [switch]$Append,
        ...
    )

    ...
    Process {
        $InputObject | ForEach-Object {
            # do stuff here, then build a custom object from the results
            $obj = New-Object -Type PSObject -Property @{
                ...
            }
            if ($PSBoundParameters.ContainsKey('Path')) {
                $obj | Export-Csv $Path -NoType -Append:$Append.IsPresent
            } else {
                $obj
            }
        }
    }
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...