检查文件扩展名是否以这个或那个结尾的最有效方法?
Most efficient way to check if file extension ends in this OR that?
我有这段代码,我非常满意:
$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
的数组做同样的事情。我不知道如何执行以下操作:
- 如果扩展名是.jpg,添加到第一个数组
- 如果扩展名是.bmp,添加到第二个数组
...为了效率起见,全部在一个循环中。我知道我可以只添加 $bmpExtensionFiles.Add(($Dirs | where {$_.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')
以下是 hashtable-based 解决方案 推广到任意数量的扩展:
Multi-pass 解决方案使用 Get-ChildItem -Filter
:
# 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
注意:乍一看,运行 Get-ChildItem -Recurse -Filter <ext>
for each 扩展似乎效率低下,但对于 small这可能仍然比下面的 single-pass Get-ChildItem -Recurse -Include <ext1>, <ext2>, ...
解决方案快:
-Filter
参数是 drive-provider-native 并在 source 处过滤,这使得它比 [=16] 更有效=] 参数.
不过遗憾的是,-Filter
只支持一个单个过滤器(通配符表达式如*.jpg
),这就是为什么多个需要通行证。
另请注意,为简单起见,在每次传递中首先收集整个匹配文件数组,然后将其作为一个整体添加到哈希表中。这样快,也memory-consuming;如果这是一个问题,请按照下面的 single-pass 解决方案逐一处理文件。
很难预测 single-pass 解决方案变得更快的确切点,因为涉及许多因素(匹配文件与 non-matching 的比率)文件,通过次数,...)。
如有疑问,请使用 Measure-Command
比较两个解决方案。
单次-使用multi-filterGet-ChildItem -Include
命令的解决方案:
# 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($_)
}
}
注意:在 PSv3 或更高版本中,您可以通过添加 -File
开关来限制仅匹配文件,从而稍微提高 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 | where {$_.extension -eq ".jpg"}))
}
但是现在,我想对一个名为 $bmpExtensionFiles
的数组做同样的事情。我不知道如何执行以下操作:
- 如果扩展名是.jpg,添加到第一个数组
- 如果扩展名是.bmp,添加到第二个数组
...为了效率起见,全部在一个循环中。我知道我可以只添加 $bmpExtensionFiles.Add(($Dirs | where {$_.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')
以下是 hashtable-based 解决方案 推广到任意数量的扩展:
Multi-pass 解决方案使用 Get-ChildItem -Filter
:
# 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
注意:乍一看,运行 Get-ChildItem -Recurse -Filter <ext>
for each 扩展似乎效率低下,但对于 small这可能仍然比下面的 single-pass Get-ChildItem -Recurse -Include <ext1>, <ext2>, ...
解决方案快:
-Filter
参数是 drive-provider-native 并在 source 处过滤,这使得它比 [=16] 更有效=] 参数.不过遗憾的是,
-Filter
只支持一个单个过滤器(通配符表达式如*.jpg
),这就是为什么多个需要通行证。
另请注意,为简单起见,在每次传递中首先收集整个匹配文件数组,然后将其作为一个整体添加到哈希表中。这样快,也memory-consuming;如果这是一个问题,请按照下面的 single-pass 解决方案逐一处理文件。
很难预测 single-pass 解决方案变得更快的确切点,因为涉及许多因素(匹配文件与 non-matching 的比率)文件,通过次数,...)。
如有疑问,请使用 Measure-Command
比较两个解决方案。
单次-使用multi-filterGet-ChildItem -Include
命令的解决方案:
# 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($_)
}
}
注意:在 PSv3 或更高版本中,您可以通过添加 -File
开关来限制仅匹配文件,从而稍微提高 Get-ChildItem
命令的效率。