2012-10-03 79 views
1

我想使用Powershell將極大的CSV文件加載到SQL Server中。該代碼還必須適用於飛行正則表達式替換,允許各種分隔符,EOR和EOF標記。對於維護,我真的很喜歡所有這些邏輯存在於Powershell中,而無需導入程序集。Powershell:圍繞流讀取器實現IdataReader包裝

爲了高效,我知道我需要使用SQLBulkCopy方法。但是,我看到的所有Powershell示例都填充了一個DataTable並將其傳遞給我,這是因爲文件大小而無法實現的。

我很確定我需要在Idatareader中包裝StreamReader,然後將其傳遞給SQLBulkcopy。我發現這幾個很好的例子,在C#中實現:
http://archive.msdn.microsoft.com/FlatFileDataReader
http://www.codeproject.com/Articles/9258/A-Fast-CSV-Reader

是否有可能不導入C#組件來完成使用本地PowerShell的這個功能?我特別難以轉換抽象類包裝。

這是我到目前爲止沒有通過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.') 

非常感謝幫助。

+0

我不知道Powershell,但在C#中,您只需將大文件分解爲更小的塊,然後一次一個塊地填充數據表並使用SqlBulkCopy。 –

+1

這不是一個更適合SSIS的任務嗎? – alroc

+0

我也想使用PowerShell來驅動工作流程。不得不調用一組臃腫,難以調試的SSIS中間包來做一個高度動態的加載似乎不符合直覺。我正在尋找更簡單的Perl類型的方法。 – Snowdogging

回答

1

如果您只想在SqlBulkCopy中使用DataReader,則可以使用Office 2007/2010附帶的ACE驅動程序,也可以單獨下載以打開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 
#) 
+0

謝謝,但我認爲這不會滿足要求。如果我記得對的,ACE不喜歡unix EOF。這種方法無法在飛行正則表達式替換或處理「信息行」。經過更多的研究,看起來像PowerShell在New-Method創建類時不允許繼承。看來我被困在使用DLL。 – Snowdogging

+0

Powershell不喜歡接口,我的意思是你需要在處理接口時動態添加或者編譯一些代碼。 –

0

我在1萬行導入大型CSV的一個DataTable,並進行批量更新。

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

Here is the link where I detail my own script on my blog,但上面的代碼概括了基本概念。我的PowerShell腳本需要4.x分鐘才能從1.1 GB CSV導入900萬行。該腳本依賴於SqlBulkCopy,[System.IO.File] :: OpenText和一個數據表。