我正在尝试阅读包含数百万行的大型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,因此我不需要读取整个内容只是为了忽略大多数数据。
答案 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来解决。这个答案主要是试图弄清楚返回的列名和值。