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.')
Большое спасибо за помощь.
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
#)
Я импортирую большие CSV по датируемым и выполняю пакетные обновления после 1 миллиона строк.
if ($dt.rows.count -eq 1000000) {
$bulkCopy.WriteToServer($dt)
$dt.Clear()
}
Вот ссылка, где я подробно описываю свой собственный сценарий в своем блоге, но приведенный выше код обрисовывает в общих чертах основную концепцию. Мой сценарий PowerShell занял 4x минуты, чтобы импортировать 9 миллионов строк из CSV-файла объемом 1,1 ГБ. Сценарий опирался на SqlBulkCopy, [System.IO.File]::OpenText и таблицу данных.