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
的数组执行相同的操作。我不知道如何执行以下操作:

  • 如果扩展名为.jpg,则添加到第一个数组中
  • 如果扩展名为.bmp,请添加到第二个数组

  • 。。。为了提高效率,所有功能都集成在一个回路中。我知道我可以只添加
    $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($_)
        }
    }