问题描述
(Get-ChildItem -File -Recurse -Path $path).Fullname
返回全名数组
(Get-ChildItem -File -Recurse -Path $path).Name
返回文件名数组
但
(Get-ChildItem -File -Recurse -Path $path).Length
只返回一个值 - 元素的数量
解决方法
您得到的一个值确实是结果数组的长度——Array 类有一个显式的 Length
property,它优先于属性枚举。
要从数组中的每个项目中获取单独的 Length
属性值,请通过管道连接到 Select-Object
或 ForEach-Object
,如下所示:
Get-ChildItem -File -Recurse -Path $path |ForEach-Object -MemberName Length
# or
Get-ChildItem -File -Recurse -Path $path |Select-Object -ExpandProperty Length
,
在您的示例中,您将获得结果数组的 Length
。
Get-ChildItem -File
返回一个 System.IO.FileInfo
数组。因此,您需要获取(选择)数组中每个条目的 Length
属性。这是通过使用 Select-Object
或仅使用 select
来完成的:
Get-ChildItem -File -Recurse -Path $path | Select-Object Length
它会给你一个包含文件长度的对象数组作为 Length
属性。您还可以选择多个属性:
Get-ChildItem -File -Recurse -Path $path | Select-Object Name,Length
,
补充Mathias R. Jessen's helpful answer:
tl;dr
使用 .ForEach()
array method 可实现简洁高效的解决方案:
# Return the files' .Length property values as a collection.
(Get-ChildItem -File -Recurse -Path $path).ForEach('Length')
正如 Mathias 的回答所指出的那样,类型本机属性 - 例如数组实例上的 .Length
- 优先于所谓的 >member enumeration 您尝试执行的操作 - 也就是说,您想要收集集合的 元素 的 .Length
属性值(数组;{{ System.IO.FileInfo
) 输出的 3}} 个实例,并将它们作为 ([object[]]
) array 返回。
-
Get-ChildItem
讨论了这种情境歧义,并建议引入一个专用运算符,比如%.
,以便您可以明确请求任一常规属性访问或成员枚举。
成员枚举的一个可能令人惊讶的方面是它应用了管道逻辑,因为它根据情况返回一个标量,即如果集合恰好包含 一个元素。
- 例如,
@(Get-Date).Year.GetType().Name
返回一个System.Int32
,而不是Object[]
,表明返回的是一个整数而不是一个包含整数的(单元素)数组 . - GitHub issue #7445 讨论了这个问题。
成员枚举不仅方便,而且快速,因为它避免了PowerShell代码中的循环/枚举。
使用 GitHub issue #6802 或 ForEach-Object
cmdlet,如 Mathias 的回答所示,绝对是功能性的 但缓慢变通办法,由于使用了不必要的管道,因此无法在给定情况下使用成员枚举用于内存中已满的输入。
因此,使用 Select-Object
- 使用您只需指定目标属性 name ('Length'
) 的重载 - 是一个 简洁且性能更好的替代方案。
- 注意:与成员枚举不同,
.ForEach()
的返回值总是一个集合,尽管不是一个array:它是[System.Collections.ObjectModel.Collection[psobject]]
类型,但是在大多数情况下它的行为类似于数组。[1]
[1] 与数组不同,这种类型的集合是可扩展的(您可以添加或删除元素)。由于元素类型为[psobject]
,每个元素通常不可见包裹在这种类型中;例如,42 -is [psobject]
是 $false
,但 @(42).ForEach({ $_ })[0] -is [psobject]
是 $true
。不幸的是,在情况下,这种几乎不可见的包装会导致不同的行为 - 请参阅.ForEach()
array method。