Powershell 基于行值筛选CSV文件
我有一个CSV文件,如下图所示,需要根据特定列上的值进行筛选。我无法Powershell 基于行值筛选CSV文件,powershell,csv,Powershell,Csv,我有一个CSV文件,如下图所示,需要根据特定列上的值进行筛选。我无法导入Csv,因为文件太大,需要很长时间。我设法使用了一个在线找到的基于Excel的解决方案,但效率极低,而且脚本运行需要几个小时 Sample.csv: A,1,2,3,4,5 B、 1、A、B、C、D C、 1,2,3,4 D、 2,1,2,3 E、 5,1,1,1 F、 8,1,1,1 我希望输出是第2列大于或等于2的所有行。即: Output.csv: D,2,1,2,3 E、 5,1,1,1 F、 8,1,1,1 如
导入Csv
,因为文件太大,需要很长时间。我设法使用了一个在线找到的基于Excel的解决方案,但效率极低,而且脚本运行需要几个小时
Sample.csv
:
A,1,2,3,4,5
B、 1、A、B、C、D
C、 1,2,3,4
D、 2,1,2,3
E、 5,1,1,1
F、 8,1,1,1
我希望输出是第2列大于或等于2的所有行。即:
Output.csv
:
D,2,1,2,3
E、 5,1,1,1
F、 8,1,1,1
如何才能为这个问题找到更有效的解决方案?试试以下方法:
Get-Content foo.csv | Where {[int]($_.Split(',')[1]) -ge 2}
获取内容将一次读取一行CSV文件。Where命令将过滤传递到其中的对象。如果evals中的条件为$true,则对象将沿着管道传递。在本例中,我们用逗号分隔行,抓取第二个字段(从零开始的索引表示索引1),将其转换为int
,然后比较-ge(大于或等于)2。请注意,在PowerShell中,其类型强制始终基于二进制运算符的左侧(LHS),如-ge
。因此,您需要确保LHS的类型为int
,以便比较int而不是字符串。尝试以下方法:
Get-Content foo.csv | Where {[int]($_.Split(',')[1]) -ge 2}
获取内容将一次读取一行CSV文件。Where命令将过滤传递到其中的对象。如果evals中的条件为$true,则对象将沿着管道传递。在本例中,我们用逗号分隔行,抓取第二个字段(从零开始的索引表示索引1),将其转换为
int
,然后比较-ge(大于或等于)2。请注意,在PowerShell中,其类型强制始终基于二进制运算符的左侧(LHS),如-ge
。因此,您需要确保LHS的类型为int
,以便比较int而不是字符串。一种方法是通过OLE访问CSV作为数据库表:
$datadir = 'C:\csv\folder'
$cs = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=$datadir;" +
'Extended Properties="text;HDR=Yes;FMT=Delimited";'
$cn = New-Object Data.OleDb.OleDbConnection
$cn.ConnectionString = $cs
$cmd = $cn.CreateCommand()
$cmd.CommandText = 'SELECT * FROM [sample.csv] WHERE [col2] >= 2'
# fill a dataset with the query result
$adapter = New-Object Data.OleDb.OleDbDataAdapter $cmd
$dataset = New-Object Data.DataSet
$adapter.Fill($dataset)
# export the first table from the dataset to a new CSV
$dataset.Tables[0] | Export-Csv 'C:\Temp\output.csv' -NoType
$cn.Close()
以上假设源CSV的路径为
C:\CSV\folder\sample.CSV
,第二列的标题为col2
。输出CSV创建为C:\temp\output.CSV
。根据需要进行调整。一种方法是通过OLE访问CSV作为数据库表:
$datadir = 'C:\csv\folder'
$cs = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=$datadir;" +
'Extended Properties="text;HDR=Yes;FMT=Delimited";'
$cn = New-Object Data.OleDb.OleDbConnection
$cn.ConnectionString = $cs
$cmd = $cn.CreateCommand()
$cmd.CommandText = 'SELECT * FROM [sample.csv] WHERE [col2] >= 2'
# fill a dataset with the query result
$adapter = New-Object Data.OleDb.OleDbDataAdapter $cmd
$dataset = New-Object Data.DataSet
$adapter.Fill($dataset)
# export the first table from the dataset to a new CSV
$dataset.Tables[0] | Export-Csv 'C:\Temp\output.csv' -NoType
$cn.Close()
以上假设源CSV的路径为
C:\CSV\folder\sample.CSV
,第二列的标题为col2
。输出CSV创建为C:\temp\output.CSV
。根据需要进行调整。您几乎重新提出了与上次相同的问题。它不起作用了吗?你的输入csv中有多少条记录?@Matt,我明白了。我的最后一个问题是基于Excel的,我正在寻找在Excel之外实现它的方法。另外,我的最后一个问题是关于删除列。在这篇文章中,它是关于基于行值进行过滤的。@WalterMitty它最多可以有500k行,每个csv有50列。你几乎要重新问上一个问题了。它不起作用了吗?你的输入csv中有多少条记录?@Matt,我明白了。我的最后一个问题是基于Excel的,我正在寻找在Excel之外实现它的方法。另外,我的最后一个问题是关于删除列。在这篇文章中,它是关于基于行值进行过滤的。@WalterMitty它最多可以有500k行,每个csv有50列。该文件显然非常庞大(最近与该用户合作)。我建议至少为此使用-ReadCount 2000
。@Matt Fair point,但这需要他拆分行manually@MathiasR.Jessen我不确定这种权衡是什么,或者它是否比使用流更快reader@Keith希尔:谢谢。这很好地发挥了作用;但是,正如Matt提到的,这些文件非常大。有没有办法将-readcount集成到这些代码中?我尝试在获取内容后将其集成为一个开关,但没有成功。提前谢谢。你可以试试这个,但我不确定它会更快:Get Content foo.csv-ReadCount 1024 | Foreach{Foreach($line in$|){if([int]($line.Split(',')[1])-ge 2){$line}
你可以利用ReadCount值来调整性能。这个文件显然很大(最近与这个用户合作过)。我建议至少为此使用-ReadCount 2000
。@Matt Fair point,但这需要他拆分行manually@MathiasR.Jessen我不确定这种权衡是什么,或者它是否比使用流更快reader@Keith希尔:谢谢。这很好地发挥了作用;但是,正如Matt提到的,这些文件非常大。有没有办法将-readcount集成到这些代码中?我尝试在获取内容后将其集成为一个开关,但没有成功。提前谢谢。你可以试试这个,但我不确定它会更快:getcontentfoo.csv-readcount1024 | Foreach{Foreach($line in$|){if([int]($line.Split(',')[1])-ge2){$line}
你可以使用ReadCount值来调整性能。