【发布时间】:2022-06-22 03:12:42
【问题描述】:
更新(22 年 6 月 21 日):请参阅下面的更新脚本,它利用了一些答案。
我正在构建一个脚本来通过大量 CSV 文件搜索$name。这些文件可以大到 67,000 KB。这是我用来搜索文件的脚本:
Powershell 脚本
基本上,我使用Import-Csv。但是,我根据文件名更改了一些内容。例如,某些文件没有标题,或者它们可能使用不同的分隔符。然后我将所有匹配项存储在$results 中,然后返回该变量。这一切都放在一个名为CSVSearch 的函数中,以便于运行。
#create function called CSV Search
function CSVSearch{
#prompt
$name = Read-Host -Prompt 'Input name'
#set path to root folder
$path = 'Path\to\root\folder\'
#get the file path for each CSV file in root folder
$files = Get-ChildItem $path -Filter *.csv | Select-Object -ExpandProperty FullName
#count files in $files
$filesCount = $files.Count
#create empty array, $results
$results= @()
#count for write-progress
$i = 0
foreach($file in $files){
Write-Progress -Activity "Searching files: $i out of $filesCount searched. $resultsCount match(es) found" -PercentComplete (($i/$files.Count)*100)
#import method changes depending on CSV file name found in $file (headers, delimiters).
if($file -match 'File1*'){$results += Import-Csv $file -Header A, Name, C, D -Delimiter '|' | Select-Object *,@{Name='FileName';Expression={$file}} | Where-Object { $_.'Name' -match $name}}
if($file -match 'File2*'){$results += Import-Csv $file -Header A, B, Name -Delimiter '|' | Select-Object *,@{Name='FileName';Expression={$file}} | Where-Object { $_.'Name' -match $name}}
if($file -match 'File3*'){$results += Import-Csv $file | Select-Object *,@{Name='FileName';Expression={$file}} | Where-Object { $_.'Name' -match $name}}
if($file -match 'File4*'){$results += Import-Csv $file | Select-Object *,@{Name='FileName';Expression={$file}} | Where-Object { $_.'Name' -match $name}}
$i++
$resultsCount = $results.Count
}
#if the loop ends and $results array is empty, return "No matches."
if(!$results){Write-Host 'No matches found.' -ForegroundColor Yellow}
#return results stored in $results variable
else{$results
Write-Host $resultsCount 'matches found.' -ForegroundColor Green
Write-Progress -Activity "Completed" -Completed}
}
CSVSearch
以下是 CSV 文件的外观。显然,下面的数据量并不等于文件的实际大小。但下面是基本结构:
CSV 文件
File1.csv
1|Moonknight|QWEPP|L
2|Star Wars|QWEPP|T
3|Toy Story|QWEPP|U
File2.csv
JKLH|1|Moonknight
ASDF|2|Star Wars
QWER|3|Toy Story
File3.csv
1,Moonknight,AA,DDD
2,Star Wars,BB,CCC
3,Toy Story,CC,EEE
File4.csv
1,Moonknight,QWE
2,Star Wars,QWE
3,Toy Story,QWE
脚本运行良好。以下是$name = Moonknight 时我会收到的输出示例:
结果示例
A : 1
Name : Moonknight
C: QWE
FileName: Path\to\root\folder\File4.csv
A : 1
Name : Moonknight
B : AA
C : DDD
FileName: Path\to\root\folder\File3.csv
A : JKLH
B : 1
Name : Moonknight
FileName: Path\to\root\folder\File2.csv
A : 1
Name : Moonknight
C : QWEPP
D : L
FileName: Path\to\root\folder\File1.csv
4 matches found.
但是,它很慢,而且我有很多文件要搜索。关于如何加快我的脚本速度的任何想法?
编辑:我必须提到。我尝试将数据导入哈希表,然后搜索哈希表,但这要慢得多。
更新的脚本 - 我的解决方案(22 年 6 月 21 日):
本次更新使用了 Santiago 下面的一些脚本。我很难解码他所做的一切,因为我是 PowerShell 的新手。所以我有点杰瑞操纵了我自己的解决方案,使用了他的很多脚本/想法。
产生巨大差异的一件事是输出$results[$i],它会在脚本运行时返回最近的匹配项。可能不是最有效的方法,但它适用于我正在尝试做的事情。谢谢!
function CSVSearch{
[cmdletbinding()]
param(
[Parameter(Mandatory)]
[string] $Name
)
$files = Get-ChildItem 'Path\to\root\folder\' -Filter *.csv -Recurse | %{$_.FullName}
$results = @()
$i = 0
foreach($file in $files){
if($file -like '*File1*'){$results += Import-Csv $file -Header A, Name, C, D -Delimiter '|' | Where-Object { $_.'Name' -match $Name} | Select-Object *,@{Name='FileName';Expression={$file}}}
if($file -like' *File2*'){$results += Import-Csv $file -Header A, B, Name -Delimiter '|' | Where-Object { $_.'Name' -match $Name} | Select-Object *,@{Name='FileName';Expression={$file}}}
if($file -like '*File3*'){$results += Import-Csv $file | Where-Object { $_.'Name' -match $Name} | Select-Object *,@{Name='FileName';Expression={$file}}}
if($file -like '*File4*'){$results += Import-Csv $file | Where-Object { $_.'Name' -match $Name} | Select-Object *,@{Name='FileName';Expression={$file}}}
$results[$i]
$i++
}
if(-not $results) {
Write-Host 'No matches found.' -ForegroundColor Yellow
return
}
Write-Host "$($results.Count) matches found." -ForegroundColor Green
}
【问题讨论】:
-
对于初学者来说,在重构之前过滤(
Where-Object应该在Select-Object之前) -
你能发布你使用哈希表的尝试吗?如果结果变慢,你可能是用错了:)
-
仅供参考:将 115 个 csv 文件合并到一个 csv 中,花了将近 10 分钟。在切换到内联 C# 和优化文件读取之间,将其缩短到大约 1 分 20 秒。单独切换到内联 C# 将时间减少到原来的三分之一。
标签: powershell csv foreach