使用Microsoft.ACE.OLEDB.12.0 OleDbConnection将CSV转换为自定义对象

时间:2016-09-11 19:12:15

标签: powershell csv oledb powershell-v4.0

我正在尝试阅读包含数百万行的大型CSV进行测试。我知道我可以使用提供程序Microsoft.ACE.OLEDB.12.0

将CSV视为数据库

使用小数据集,我能够使用@" id,first_name,last_name,email,ip_address 1,Edward,Richards,erichards0@businessweek.com,201.133.112.30 2,Jimmy,Scott,jscott1@clickbank.net,103.231.149.144 3,Marilyn,Williams,mwilliams2@chicagotribune.com,52.180.157.43 4,Frank,Morales,fmorales3@google.ru,218.175.165.205 5,Chris,Watson,cwatson4@ed.gov,75.251.1.149 6,Albert,Ross,aross5@abc.net.au,89.56.133.54 7,Diane,Daniels,ddaniels6@washingtonpost.com,197.156.129.45 8,Nancy,Carter,ncarter7@surveymonkey.com,75.162.65.142 9,John,Kennedy,jkennedy8@tumblr.com,85.35.177.235 10,Bonnie,Bradley,bbradley9@dagondesign.com,255.67.106.193 "@ | Set-Content .\test.csv $conn = New-Object System.Data.OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source='C:\Users\Matt';Extended Properties='Text;HDR=Yes;FMT=Delimited';") $cmd=$conn.CreateCommand() $cmd.CommandText="Select * from test.csv where first_name like '%n%'" $conn.open() $data = $cmd.ExecuteReader() $data | ForEach-Object{ [pscustomobject]@{ id=$_.GetValue(0) first_name=$_.GetValue(1) last_name=$_.GetValue(2) ip_address=$_.GetValue(4) } } $cmd.Dispose() $conn.Dispose() 以位置方式读取行内容。我很难找到一个更好的读取数据(假设有一个。)。如果我事先知道列名,这很容易。但是,如果我不知道它们,我将不得不在文件的第一行读取以获取看似愚蠢的数据。

$cmd.ExecuteReader()

有没有更好的方法来处理(\d+) x (\d+) x (\d+)的输出?很难获得CSV导入的信息。大多数Web处理从SQL数据库使用此提供程序导出到CSV。这里的逻辑将应用于一个大型CSV,因此我不需要读取整个内容只是为了忽略大多数数据。

1 个答案:

答案 0 :(得分:0)

我应该仔细研究TechNet for the OleDbDataReader Class。有一些方法和属性可以帮助理解从SQL语句返回的数据。

  •   

    FieldCount:获取当前行中的列数。

    所以,如果没有别的,你知道你的行有多少列。

  •   

    Item[Int32]:给定列序号,以原始格式获取指定列的值。

    我可以使用它从每一行拉回数据。这似乎与GetValue()相同。

  •   

    GetName(Int32):获取指定列的名称。

    因此,如果您不知道列的名称是什么,那么您可以使用它来从给定索引中获取该列。

还有许多其他方法和一些属性,但如果您不确定csv中包含哪些数据(假设您不希望事先手动验证),那么这些方法就足以说明问题。所以,知道这一点,获得相同信息的更有活力的方式就是......

$data | ForEach-Object{

    # Save the current row as its own object so that it can be used in other scopes
    $dataRow = $_
    # Blank hashtable that will be built into a "row" object
    $properties = @{}

    # For every field that exists we will add it name and value to the hashtable
    0..($dataRow.FieldCount - 1) | ForEach-Object{
        $properties.($dataRow.GetName($_)) = $dataRow.Item($_)
    }

    # Send the newly created object down the pipeline.
    [pscustomobject]$properties
}

$cmd.Dispose()
$conn.Dispose()

唯一的缺点是列的输出可能与原始CSV的顺序不同。这可以通过将行名称保存在单独的变量中并使用管道末尾的Select来解决。这个答案主要是试图弄清楚返回的列名和值。