使用 Microsoft.ACE.OLEDB.12.0 OleDbConnection 将 CSV 转换为自定义对象
Converting CSV to custom object using a Microsoft.ACE.OLEDB.12.0 OleDbConnection
我正在尝试读取包含数百万行的大型 CSV 文件以进行测试。我知道我可以使用提供程序 Microsoft.ACE.OLEDB.12.0
将 CSV 视为数据库
使用小型数据集,我可以使用 .GetValue(int)
定位读取行内容。我很难找到更好的方法来读取数据(假设甚至有一个。)。如果我事先知道列名,这很容易。但是,如果我不认识他们,我将不得不阅读文件的第一行以获取看起来很愚蠢的数据。
@"
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()
的输出?很难找到 CSV 导入的信息。大多数 Web 处理使用此提供程序从 SQL 数据库导出到 CSV。这里的逻辑将应用于大型 CSV,这样我就不需要为了忽略大部分数据而阅读整个内容。
我应该仔细看看 TechNet for the OleDbDataReader Class。有一些方法和属性有助于理解从 SQL 语句返回的数据。
-
FieldCount
: Gets the number of columns in the current row.
因此,如果不出意外,您知道您的行有多少列。
-
Item[Int32]
: Gets the value of the specified column in its native format given the column ordinal.
我可以用它从每一行中提取数据。这似乎与 GetValue()
.
相同
-
GetName(Int32)
: Gets the name of the specified column.
因此,如果您不知道该列的名称,您可以使用它从给定索引中获取它。
还有许多其他方法和一些属性,但如果您不确定 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 来解决。这个答案主要是试图理解返回的列名和值。
我正在尝试读取包含数百万行的大型 CSV 文件以进行测试。我知道我可以使用提供程序 Microsoft.ACE.OLEDB.12.0
将 CSV 视为数据库使用小型数据集,我可以使用 .GetValue(int)
定位读取行内容。我很难找到更好的方法来读取数据(假设甚至有一个。)。如果我事先知道列名,这很容易。但是,如果我不认识他们,我将不得不阅读文件的第一行以获取看起来很愚蠢的数据。
@"
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()
的输出?很难找到 CSV 导入的信息。大多数 Web 处理使用此提供程序从 SQL 数据库导出到 CSV。这里的逻辑将应用于大型 CSV,这样我就不需要为了忽略大部分数据而阅读整个内容。
我应该仔细看看 TechNet for the OleDbDataReader Class。有一些方法和属性有助于理解从 SQL 语句返回的数据。
-
FieldCount
: Gets the number of columns in the current row.因此,如果不出意外,您知道您的行有多少列。
-
Item[Int32]
: Gets the value of the specified column in its native format given the column ordinal.我可以用它从每一行中提取数据。这似乎与
相同GetValue()
. -
GetName(Int32)
: Gets the name of the specified column.因此,如果您不知道该列的名称,您可以使用它从给定索引中获取它。
还有许多其他方法和一些属性,但如果您不确定 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 来解决。这个答案主要是试图理解返回的列名和值。