Arrays 检查文件扩展名是否以这个或那个结尾的最有效方法是什么?
我有一个我非常满意的代码:Arrays 检查文件扩展名是否以这个或那个结尾的最有效方法是什么?,arrays,file,powershell,powershell-2.0,get-childitem,Arrays,File,Powershell,Powershell 2.0,Get Childitem,我有一个我非常满意的代码: $jpgExtensionFiles = New-Object System.Collections.ArrayList $AllDrives = Get-PSDrive foreach ($Drive in $AllDrives) { $Dirs = Get-ChildItem $Drive.Root -Recurse -ErrorAction SilentlyContinue $jpgExtensionFiles.Add(($Dirs
$jpgExtensionFiles = New-Object System.Collections.ArrayList
$AllDrives = Get-PSDrive
foreach ($Drive in $AllDrives) {
$Dirs = Get-ChildItem $Drive.Root -Recurse -ErrorAction SilentlyContinue
$jpgExtensionFiles.Add(($Dirs | where {$_.extension -eq ".jpg"}))
}
但是现在,我想对名为$bmpExtensionFiles
的数组执行相同的操作。我不知道如何执行以下操作:
。。。为了提高效率,所有功能都集成在一个回路中。我知道我可以只添加
$bmpExtensionFiles.add($Dirs | where{$\uu.extension-eq.bmp“}))
,但是有更有效的方法吗?我需要与PowerShell v2兼容的版本。您可以使用switch语句,然后如果您想在以后添加更多类型,则可以轻松扩展:
ForEach ($Dir in $Dirs)
{
Switch ($Dir.Extension)
{
".jpg" {$jpgExtensionFiles.Add($Dir)}
".bmp" {$bmpExtensionFiles.Add($Dir)}
}
}
未进行广泛测试,但应非常有效
$jpgExtensionFiles,$bmpExtensionfiles = (Get-ChildItem $Drive.Root -Recurse -include *.jpg,*.bmp -ErrorAction SilentlyContinue).where({$_.extension -eq '.jpg'},'split')
以下是基于哈希表的解决方案,可推广到任意数量的扩展:
使用
获取子项-过滤器的多通道解决方案
:
注意:乍一看,为每个扩展运行Get ChildItem-Recurse-Filter
似乎效率低下,但对于少量扩展,这可能仍然比下面的单次传递Get ChildItem-Recurse-Include,
解决方案快:
参数是驱动器提供程序本机的,并在源位置进行筛选,这使得它比-Filter
参数效率更高-Include
- 不幸的是,
只支持一个过滤器(通配符表达式,如-Filter
),这就是为什么需要多个过程*.jpg
当有疑问时,使用
Measure命令
比较两种解决方案
使用多过滤器的单程解决方案
Get ChildItem-Include
命令:
注意:在PSv3或更高版本中,您可以通过添加
-File
开关来限制仅匹配文件,从而略微提高Get ChildItem
命令的效率。这很有效!您能否简单地解释一下,与我在示例中使用的where
关键字相反,使用嵌套的开关执行foreach
的性能影响?在您的示例中,当您将$Dirs
管道输送到where
时,它实际上是一个嵌套循环($dirs
数组中的每个对象都通过管道传递到其中的)。如果您按照原始问题为.bmp
添加第二行,它将处理整个数组两次。在foreach中使用switch意味着无论您检查了多少扩展名,它都只在数组中循环一次。很好,完全如我所想。谢谢您的确认!我将使用扩展名索引的列表数组改为打开。不需要“如果”或“开关”,那么,@DavidBrabant你能提供这个解决方案让我看看吗?然后你能解释一下为什么你描述的哈希表会更有效吗?这比另一个答案更有效吗?你能解释一下发生了什么吗?另外,我测试了你的答案,所有的文件似乎都进入了$bmpExtensionfiles
数组。应该是这样的。它正在对另一个解决方案进行早期筛选,而不是后期筛选。V4中添加了.where()方法,这里可以找到一个很好的解释:。我在本地系统上对C驱动器进行了测试,得到了预期的结果。啊,我正在寻找与V2兼容的解决方案。
# Initialize a hashtable for all extexnsions of interest:
# Key is the extension name, value is an array list to be filled
# with the files ([System.IO.FileInfo] instances) having that extension.
$htFilesByType = @{
'.jpg' = New-Object System.Collections.ArrayList
'.bmp' = New-Object System.Collections.ArrayList
}
# Get the list of all filesystem PS drives.
$AllFsDrives = Get-PSDrive -PSProvider FileSystem
# Loop over all filesystem drives.
foreach ($Drive in $AllFsDrives) {
# Loop over all extensions and add files with that extension to the hashtable.
foreach ($ext in $htFilesByType.Keys) {
# Get all files with the extension at hand at once and add them
# to the relevant hashtable entry.
# Note: The .Add() method returns a value, which we're not interested in,
# hence the `$null = ...`.
$null = $htFilesByType[$ext].Add(
(Get-ChildItem -Filter "*$ext" $Drive.Root -Recurse -ErrorAction SilentlyContinue)
)
}
}
# Output the filled hashtable.
$htFilesByType
# Construct the array of wildcard expressions to use with -Include;
# e.g., @( '*.jpg', '*.bmp' )
$includes = $htFilesByType.keys -replace '^', '*'
foreach ($Drive in $AllFsDrives) {
# Look for files with any of the extensions of interest.
Get-ChildItem -Include $includes $Drive.Root -Recurse -ErrorAction SilentlyContinue |
ForEach-Object {
# Add to the appropriate array list based on the matching file's extension.
$null = $htFilesByType[$_.Extension].Add($_)
}
}