简体   繁体   English

使用 PowerShell 从文件夹中获取文件名的最快\最好的方法是什么?

[英]What is the fastest\best way to get file names from a folder using PowerShell?

The directory has 20k folders in it.该目录中有 20k 个文件夹。 In these folders there are subfolders and some files.在这些文件夹中有子文件夹和一些文件。 I don't need to look into the subfolders.我不需要查看子文件夹。 I need to get all the files with .EIA extension from the folders.我需要从文件夹中获取所有扩展名为 .EIA 的文件。

I know I could use Get-Item, Get-ChildItem for this but these cmdlet are too slow in the getting the data.我知道我可以为此使用 Get-Item、Get-ChildItem,但是这些 cmdlet 在获取数据方面太慢了。 Also, this script has to run every hour therefore, it cannot be taking superlong.此外,此脚本必须每小时运行一次,因此它不能花费超长。

I was trying to use [System.IO.File]::GetFiles($path) but this gives an error我试图使用[System.IO.File]::GetFiles($path)但这会出错

 Method invocation failed because [System.IO.File] does not contain a method named 'GetFile'

I have also tried我也试过

$pathEia = "\\Sidney2\MfgLib\AidLibTest\*\*.EIA"
 [System.IO.File]::GetFiles($pathEia)

This also throws an error:这也会引发错误:

 Exception calling "GetFiles" with "1" argument(s): "The filename, directory name, or volume label
     | syntax is incorrect. : '\\Sidney2\MfgLib\AidLibTest\*\*.EIA'"

I am using PowerShell Core 7.2 .Net Framework 4.8 Any help is appreciated.我正在使用 PowerShell Core 7.2 .Net Framework 4.8 任何帮助表示赞赏。 Thanks in advance.提前致谢。

Very similar to mklement0's helpful answer but using the instance methods from DirectoryInfo .mklement0 的有用答案非常相似,但使用的是DirectoryInfo的实例方法。

EnumerationOptions is available starting from .NET Core 2.1 . EnumerationOptions.NET Core 2.1开始可用。 This class has the property IgnoreInaccessible set to $true by default, in prior versions an exception would cause the enumeration to Stop :此类的属性IgnoreInaccessible默认设置为$true在以前的版本中,异常会导致枚举停止

...skip files or directories when access is denied (for example, UnauthorizedAccessException or SecurityException ). ...当访问被拒绝时跳过文件或目录(例如, UnauthorizedAccessExceptionSecurityException )。

This answer requires PowerShell Core 7+ .这个答案需要 PowerShell Core 7+

# Skip the following Attributes:
#   2.    Hidden
#   4.    System
#   1024. ReparsePoint
#   512.  SparseFile

$enum = [IO.EnumerationOptions]@{
    RecurseSubdirectories = $false # Set to `$true` if you need to do a recursive search
    AttributesToSkip      = 2, 4, 1024, 512
}

$start  = [IO.DirectoryInfo]::new('\\Sidney2\MfgLib\AidLibTest')
$result = foreach($dir in $start.EnumerateDirectories()) {
    $dir.GetFiles('*.EIA', $using:enum)
}
$result | Format-Table

If you need to do a recursive search on the subfolders (if RecurseSubdirectories = $true ), you can consider using multi-threading with ForEach-Object -Parallel .如果您需要对子文件夹进行递归搜索(如果RecurseSubdirectories = $true ),您可以考虑使用ForEach-Object -Parallel多线程

$start  = [IO.DirectoryInfo]::new('\\Sidney2\MfgLib\AidLibTest')
$result = $start.EnumerateDirectories() | ForEach-Object -Parallel {
    $_.GetFiles('*.EIA', $using:enum)
}
$result | Format-Table

It's important to note that, using a parallel loop may or may not have an edge over an efficient linear loop (such as foreach ), as mklement0 notes in his comment :重要的是要注意,使用并行循环可能会或可能不会比有效的线性循环(例如foreach )具有优势,正如mklement0 在他的评论中指出的那样

Parallelism works best for different disks/shares/computers.并行性最适合不同的磁盘/共享/计算机。

Try the following:尝试以下操作:

$path = '\\Sidney2\MfgLib\AidLibTest'
$allFilePathsOfInterest =
  foreach ($dir in [System.IO.Directory]::GetDirectories($path)) {
    [System.IO.Directory]::GetFiles($dir, '*.EIA')
  }

Given that the input directory path is a full path, $allFilesOfInterest is an array of full file paths too.鉴于输入目录路径是完整路径, $allFilesOfInterest也是完整文件路径的数组。

If you want the file names only, use the instance methods of the [System.IO.DirectoryInfo] type instead of the static methods of the[System.IO.Directory] type, which allows you to access the .Name property of the [System.IO.FileInfo] instances being returned:如果您只需要文件,请使用 [System.IO.DirectoryInfo] 类型的实例方法而不是[System.IO.Directory] [System.IO.DirectoryInfo]​​类型的静态方法,这允许您访问[System.IO.FileInfo].Name属性[System.IO.FileInfo]实例被返回:

$path = '\\Sidney2\MfgLib\AidLibTest'
$allFileNamesOfInterest =
  foreach ($dir in [System.IO.DirectoryInfo]::new($path).GetDirectories()) {
    $dir.GetFiles('*.EIA').Name
  }
  • Note the two-step approach - get subdirectories first, then examine their files - because I'm not aware of a standard .NET API that would allow you to process wildcards across levels of the hierarchy (eg, \\Sidney2\MfgLib\AidLibTest\*\*.EIA' ).请注意两步方法 - 首先获取子目录,然后检查它们的文件 - 因为我不知道允许您跨层次结构级别处理通配符的标准 .NET API(例如, \\Sidney2\MfgLib\AidLibTest\*\*.EIA' )。

  • If you need more control over the enumeration of the files and directories, the GetDirectories and GetFiles methods offer overloads that accept a System.IO.EnumerationOptions instance, but, unfortunately, in PowerShell (Core) 7+ / .NET (Core) only:如果您需要对文件和目录的枚举进行更多控制, GetDirectoriesGetFiles方法提供了接受System.IO.EnumerationOptions实例的重载,但不幸的是,仅在 PowerShell (Core) 7+ / .NET (Core) 中:

    • Windows PowerShell / .NET Framework only offers overloads with a System.IO.SearchOption instance, but the only thing that controls is whether the enumeration is recursive . Windows PowerShell / .NET Framework 仅提供带有System.IO.SearchOption实例的重载,但唯一控制的是枚举是否是递归的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM