Powershell 基于行值筛选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文件,如下图所示,需要根据特定列上的值进行筛选。我无法
导入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值来调整性能。