Arrays Get-ChildItem.Length错误
我正在编写一个递归函数,它遍历一个目录并复制其中的每个文件和文件夹。我在函数中的第一个检查是查看传入的路径是否有子路径。为了找到答案,我使用以下方法:Arrays Get-ChildItem.Length错误,arrays,powershell,member-enumeration,Arrays,Powershell,Member Enumeration,我正在编写一个递归函数,它遍历一个目录并复制其中的每个文件和文件夹。我在函数中的第一个检查是查看传入的路径是否有子路径。为了找到答案,我使用以下方法: [array]$arrExclude = @("Extras") Function USBCopy { Param ([string]$strPath, [string]$strDestinationPath) try { $pathChildren = Get-ChildItem -Path $strPath
[array]$arrExclude = @("Extras")
Function USBCopy
{
Param ([string]$strPath, [string]$strDestinationPath)
try
{
$pathChildren = Get-ChildItem -Path $strPath
if($pathChildren.Length -gt 0)
{
foreach($child in $pathChildren)
{
if($arrExclude -notcontains $child)
{
$strPathChild = "$strPath\$child"
$strDestinationPathChild = "$strDestinationPath\$child"
Copy-Item $strPathChild -Destination $strDestinationPathChild
USBCopy $strPathChild $strDestinationPathChild
}
}
}
}
catch
{
Write-Error ("Error running USBCopy: " + $Error[0].Exception.Message)
}
}
在大多数情况下,我的函数是有效的,但我的代码会说一个目录是空的,而实际上其中有一个文件。当我调试我的函数时,变量会说文件夹有子文件夹,但变量的长度是0。有人知道如何解决这个问题吗?尝试
$pathChildren.Count
而不是$pathChildren.Length
——它将返回数组中的项数。与以前一样,多次在对这个问题的简短评论中提供了关键指针(他还帮助完善了这个答案):
使用数组子表达式操作符@(…)
,可以确保即使只输出一个对象,所包含的任何命令输出都被视为数组,因此.Length
保证是数组的.Length
属性
但是,在PSv3+中,访问.Count
而不是.Length
,如中所示,也起作用-见下文
如果没有@(…)
,则结果可能是单个对象,因为PowerShell会自动打开仅包含1个对象的输出集合,从而只生成一个对象,这意味着:
- 小于等于PSv2
- 如果一个对象恰好具有
属性,则返回其值。.Length
在本例中,如果返回的唯一对象表示一个文件(一个
实例)(如果目录正好包含一个文件,并且没有子目录,除了隐藏项,则反过来也是如此)。[System.IO.FileInfo]
实例的[System.IO.FileInfo]
属性以字节为单位返回文件大小。值.Length
表示文件为空。0
(如果返回的唯一对象是目录(一个
实例,[System.IO.DirectoryInfo]
将返回.Length
,因为此类实例没有$null
属性。).Length
- 如果一个对象恰好具有
- 在PSv3+中,如果您使用
,则不再严格需要解决方法,因为您甚至可以将标量(单个对象)视为数组,并使用隐式.Count
/.Length
[1] 属性和索引到的能力(例如,.Count
),但有一些警告[0]
- 如果
或更高版本有效,访问Set StrictMode-Version 2
和.Length
属性时,手头的标量上实际上不存在的属性会导致错误。.Count
然而,这种行为是非常不幸的,因为这些属性应该被认为是隐式存在的——如果你同意的话,让别人听到你的声音 - 如果标量本身有一个属性,如
或.Length
或支持索引,则该属性优先于-这就是为什么在这种情况下必须使用.Count
(如上所述,.Count
实例有一个[System.IO.FileInfo]
属性报告以字节为单位的文件大小);示例见下文.Length
- 使用
可以避免此类冲突,因为结果总是一个数组@(…)
- 成员枚举是统一的补充,它允许您应用成员(属性或方法)集合中包含的项的集合级别,在这种情况下,对集合中的每个项隐式访问成员,并将结果值作为数组返回;请参见下面的示例。
要解决成员枚举的名称冲突,需要一种不同的方法-请参阅我的
PSv3+统一集合处理示例
[1] 正如PetSerAl指出的,在PSv5.1之前,数组的
.Count
属性是由PowerShell的ETS(扩展类型系统-请参阅)添加的.Length
别名属性。
但是,自从PSv3显式实现以来,实际上并不需要此alias属性。PowerShell也公开了.NET接口类型成员,提供了对数组类型的ICollection.Count
属性的访问。因此,v6将不再具有alias属性,此时.Count
将直接访问I收集.计数
-请参阅。请注意,在调用“伪”数组(标量)上的
.Count
时,PowerShell magic仍然会涉及。$pathChildren=@(Get ChildItem-Path$strPath)
OP的可能副本不需要使用PSv2来获得0的可变长度,空文件也会有相同的结果。不管怎样,PetSerAl关于@(…)
的建议和你在上面扩展的答案肯定是一个更好的实践。(现在)我认为使用.Count
不仅可以在PSv3+中很好地工作,而且可以说它比@(…).Length
更加惯用,因为它利用了PSv3+对集合和标量的统一处理(尽管仍然有必要了解潜在的问题,特别是这里调用的.Count
不是实际的数组)@mklement0感谢您深入了解此操作的方式/原因。我知道避免在数组中使用.Length
,但我从未花时间理解其背后的原因/方式。您的答案非常有用。
$pathChildren = @(Get-ChildItem -Path $strPath)
PS> (666).Length
1 # Scalar 666 was implicitly treated as a collection of length 1
PS> (666).Count
1 # Ditto - ** .Count is preferable, because it less often means something else **
# Caveat: A *string* scalar has a native .Length property
PS> ('666').Length; ('666').Count
3 # .Length: The string types's native property: the number of *characters*
1 # .Count: PowerShell's implicit collection handling: 1 *element*
PS> (666)[0]; (666)[-1]
666 # Index [0] always yields the scalar itself.
666 # Ditto for [-1], the *last* element.
# Member enumeration example: get the .Day property value from each
# [datetime] instance stored in an array.
PS> ((Get-Date), (Get-Date).AddDays(-1)).Day
20
19