Powershell: реализация оболочки IdataReader для потокового чтения

Я пытаюсь загрузить очень большие файлы CSV в SQL Server с помощью Powershell. Код также должен применять замены регулярных выражений «на лету», допускать различные разделители, маркеры EOR и EOF. Для обслуживания мне бы очень хотелось, чтобы вся эта логика существовала в Powershell без импорта сборок.

Чтобы быть эффективным, я знаю, что мне нужно использовать метод SQLBulkCopy. Но все примеры Powershell, которые я вижу, заполняют DataTable и передают его, что для меня невозможно из-за размера файла.

Я почти уверен, что мне нужно обернуть StreamReader в Idatareader, а затем передать это в SQLBulkcopy. Я нашел пару отличных примеров реализации этого на C#:
http://archive.msdn.microsoft.com/FlatFileDataReader
http://www.codeproject.com/Articles/9258/A-Fast-CSV-Reader

Можно ли выполнить эту функцию с помощью собственного PowerShell без импорта сборки C#? Мне особенно трудно преобразовать оболочку абстрактного класса.

Это код, который у меня есть до сих пор, который не передает IdataReader и нарушает ограничения памяти.

function Get-CSVDataReader()
{
param (
   [string]$path
)
    $parsedData = New-Object 'System.Collections.Generic.List[string]'
    #List<string[]> parsedData = new List<string[]>()

    $sr = new-object IO.StreamReader($path)

    while ($line = $sr.ReadLine())
    {
        #regex replace and other logic here
        $parsedData.Add($line.Split(','))
    }

    ,$parsedData #if this was an idatareader, the comma keeps it from exploding
}

$MyReader = Get-CSVDataReader('This should not fill immediately.  It needs a Read Method.')

Большое спасибо за помощь.


person Snowdogging    schedule 03.10.2012    source источник
comment
Я не знаю о Powershell, но в C# вы просто разбиваете большой файл на более мелкие фрагменты, затем берете фрагменты по одному, заполняете таблицу данных и используете SqlBulkCopy.   -  person Louis Kottmann    schedule 03.10.2012
comment
Разве эта задача не лучше подходит для SSIS?   -  person alroc    schedule 03.10.2012
comment
Я также хочу использовать PowerShell для управления рабочим процессом. Необходимость вызывать набор раздутых, сложных для отладки пакетов SSIS посередине для выполнения высокодинамичной загрузки кажется нелогичной. Я ищу более простой подход типа Perl.   -  person Snowdogging    schedule 03.10.2012


Ответы (2)


Если все, что вы хотите сделать, это использовать DataReader с SqlBulkCopy, вы можете использовать драйверы ACE, которые поставляются с Office 2007/2010, а также доступны для отдельной загрузки, чтобы открыть соединение OLEDB с CSV-файлом, открыть ридер и вызвать WriteToServer

$ServerInstance = "$env:computername\sql1"
$Database = "tempdb"
$tableName = "psdrive"
$ConnectionString = "Server={0};Database={1};Integrated Security=True;" -f $ServerInstance,$Database
$filepath = "C:\Users\Public\bin\"

get-psdrive | export-csv ./psdrive.csv -NoTypeInformation -Force

$connString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=`"$filepath`";Extended Properties=`"text;HDR=yes;FMT=Delimited`";"

$qry = 'select * from [psdrive.csv]'

$conn = new-object System.Data.OleDb.OleDbConnection($connString)
$conn.open()
$cmd = new-object System.Data.OleDb.OleDbCommand($qry,$conn) 
$dr = $cmd.ExecuteReader()

$bulkCopy = new-object ("Data.SqlClient.SqlBulkCopy") $connectionString
$bulkCopy.DestinationTableName = $tableName
$bulkCopy.WriteToServer($dr)

$dr.Close()
$conn.Close()

#CREATE TABLE [dbo].[psdrive](
#   [Used] [varchar](1000) NULL,
#   [Free] [varchar](1000) NULL,
#   [CurrentLocation] [varchar](1000) NULL,
#   [Name] [varchar](1000) NULL,
#   [Provider] [varchar](1000) NULL,
#   [Root] [varchar](1000) NULL,
#   [Description] [varchar](1000) NULL,
#   [Credential] [varchar](1000) NULL,
#   [DisplayRoot] [varchar](1000) NULL
#)
person Chad Miller    schedule 03.10.2012
comment
Спасибо, но я не думаю, что это удовлетворит требованиям. Если я правильно помню, ACE не любит unix EOF. И этот подход не может выполнять какие-либо замены регулярных выражений на лету или обрабатывать информационные строки. После дополнительных исследований выяснилось, что powershell не допускает наследования при создании класса с помощью New-Method. Похоже, я застрял с использованием DLL. - person Snowdogging; 04.10.2012
comment
Powershell не любит интерфейсы, под этим я подразумеваю, что вам нужно либо добавить dll, либо скомпилировать некоторый код на лету при работе с интерфейсами. - person Chad Miller; 04.10.2012

Я импортирую большие CSV-файлы с помощью таблицы данных и выполняю пакетные обновления после 1 миллиона строк.

if ($dt.rows.count -eq 1000000) {
    $bulkCopy.WriteToServer($dt)
    $dt.Clear()
}

Здесь — это ссылка, по которой я подробно описываю свой сценарий в своем блоге, но приведенный выше код описывает основную концепцию. Моему скрипту PowerShell потребовалось 4,x минуты, чтобы импортировать 9 миллионов строк из CSV-файла объемом 1,1 ГБ. Сценарий опирался на SqlBulkCopy, [System.IO.File]::OpenText и таблицу данных.

person Chrissy LeMaire    schedule 04.07.2014