【问题标题】:Powershell: Implementing an IdataReader wrapper around streamreaderPowershell:围绕流读取器实现 IdataReader 包装器
【发布时间】:2012-10-03 16:50:34
【问题描述】:

我正在尝试使用 Powershell 将超大的 CSV 文件加载到 SQL Server 中。该代码还必须即时应用正则表达式替换,允许使用各种分隔符、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

是否可以在不导入 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.')

非常感谢您的帮助。

【问题讨论】:

  • 我不了解 Powershell,但在 C# 中,您只需将大文件分成较小的块,然后一次取一个块,填充数据表并使用 SqlBulkCopy。
  • 这不是更适合 SSIS 的任务吗?
  • 我还想使用 PowerShell 来驱动工作流。不得不在中间调用一组臃肿、难以调试的 SSIS 包来进行高度动态加载,这似乎违反直觉。我正在寻找一种更简单的 Perl 类型的方法。

标签: powershell streamreader sqlbulkcopy idatareader


【解决方案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
#)

【讨论】:

  • 谢谢,但我认为这不能满足要求。如果我没记错的话,ACE 不喜欢 unix EOF。并且该方法不能进行任何动态正则表达式替换或处理“信息行”。经过更多研究,在使用 New-Method 创建类时,powershell 似乎不允许继承。看来我无法使用 DLL。
  • Powershell 不喜欢接口,我的意思是你在处理接口时需要添加类型的 dll 或动态编译一些代码。
【解决方案2】:

我正在通过数据表导入大型 CSV,并在 100 万行后执行批量更新。

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 和一个数据表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-19
    • 1970-01-01
    • 1970-01-01
    • 2012-05-23
    • 2023-03-17
    • 1970-01-01
    相关资源
    最近更新 更多