我正在構建一個腳本來搜索$name大量 CSV 檔案。這些檔案可以大到 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.
但是,它很慢,而且我有很多檔案要搜索。關于如何加快我的腳本速度的任何想法?
編輯:我必須提到。我嘗試將資料匯入哈希表,然后搜索哈希表,但這要慢得多。
uj5u.com熱心網友回復:
試試這個,應該會快一點。Select-Object必須重建你的物件,如果你在過濾之前使用它,你實際上是在重新創建你的整個 CSV,你想在重建它之前先過濾( Where-Object/ )。.Where
.Where應該比Where-Object這里更快,需要注意的是內在方法要求集合已經存在于記憶體中,沒有管道處理和流。
Write-Progress只會減慢您的腳本,最好將其洗掉。
最后,您可以使用splatting來避免出現多個if條件。
function CSVSearch {
[cmdletbinding()]
param(
[Parameter(Mandatory)]
[string] $Name,
[Parameter()]
[string] $Path = 'Path\to\root\folder\'
)
$param = @{
File1 = @{ Header = 'A', 'Name', 'C', 'D'; Delimiter = '|' }
File2 = @{ Header = 'A', 'B', 'Name' ; Delimiter = '|' }
File3 = @{}; File4 = @{} # File3 & 4 should have headers ?
}
$results = foreach($file in Get-ChildItem . -Filter file*.csv) {
$thisparam = $param[$file.BaseName]
$thisparam['LiteralPath'] = $file.FullName
(Import-Csv @thisparam).where{ $_.Name -match $name } |
Select-Object *, @{Name='FileName';Expression={$file}}
}
if(-not $results) {
Write-Host 'No matches found.' -ForegroundColor Yellow
return
}
Write-Host "$($results.Count) matches found." -ForegroundColor Green
$results
}
CSVSearch -Name Moonknight
如果您希望函式在找到結果時對其進行流式傳輸,您可以使用Filter,這是一種非常有效的過濾技術,肯定比Where-Object:
function CSVSearch {
[cmdletbinding()]
param(
[Parameter(Mandatory)]
[string] $Name,
[Parameter()]
[string] $Path = 'Path\to\root\folder\'
)
begin {
$param = @{
File1 = @{ Header = 'A', 'Name', 'C', 'D'; Delimiter = '|' }
File2 = @{ Header = 'A', 'B', 'Name' ; Delimiter = '|' }
File3 = @{}; File4 = @{} # File3 & 4 should have headers ?
}
$counter = [ref] 0
filter myFilter {
if($_.Name -match $name) {
$counter.Value
$_ | Select-Object *, @{N='FileName';E={$file}}
}
}
}
process {
foreach($file in Get-ChildItem $path -Filter *.csv) {
$thisparam = $param[$file.BaseName]
$thisparam['LiteralPath'] = $file.FullName
Import-Csv @thisparam | myFilter
}
}
end {
if(-not $counter.Value) {
Write-Host 'No matches found.' -ForegroundColor Yellow
return
}
Write-Host "$($counter.Value) matches found." -ForegroundColor Green
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/475546.html
上一篇:Powershell-Invoke-RestMethod獲取所有鏈接
下一篇:將陣列中的屬性拆分為多個屬性
